merge linus into release branch
authorLen Brown <len.brown@intel.com>
Thu, 29 Jun 2006 23:57:46 +0000 (19:57 -0400)
committerLen Brown <len.brown@intel.com>
Thu, 29 Jun 2006 23:57:46 +0000 (19:57 -0400)
Conflicts:

drivers/acpi/acpi_memhotplug.c

1387 files changed:
CREDITS
Documentation/Changes
Documentation/DocBook/Makefile
Documentation/DocBook/genericirq.tmpl [new file with mode: 0644]
Documentation/DocBook/kernel-api.tmpl
Documentation/IRQ.txt [new file with mode: 0644]
Documentation/RCU/torture.txt
Documentation/README.DAC960
Documentation/feature-removal-schedule.txt
Documentation/filesystems/devfs/ChangeLog [deleted file]
Documentation/filesystems/devfs/README [deleted file]
Documentation/filesystems/devfs/ToDo [deleted file]
Documentation/filesystems/devfs/boot-options [deleted file]
Documentation/initrd.txt
Documentation/ioctl-number.txt
Documentation/kernel-parameters.txt
Documentation/keys-request-key.txt
Documentation/keys.txt
Documentation/pi-futex.txt [new file with mode: 0644]
Documentation/robust-futexes.txt
Documentation/rt-mutex-design.txt [new file with mode: 0644]
Documentation/rt-mutex.txt [new file with mode: 0644]
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/video4linux/README.pvrusb2 [new file with mode: 0644]
Documentation/watchdog/pcwd-watchdog.txt
Documentation/watchdog/src/watchdog-simple.c [new file with mode: 0644]
Documentation/watchdog/src/watchdog-test.c [new file with mode: 0644]
Documentation/watchdog/watchdog-api.txt
Documentation/watchdog/watchdog.txt
arch/alpha/kernel/irq.c
arch/alpha/kernel/irq_alpha.c
arch/alpha/kernel/irq_i8259.c
arch/alpha/kernel/irq_pyxis.c
arch/alpha/kernel/irq_srm.c
arch/alpha/kernel/pci.c
arch/alpha/kernel/setup.c
arch/alpha/kernel/sys_alcor.c
arch/alpha/kernel/sys_cabriolet.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_eb64p.c
arch/alpha/kernel/sys_eiger.c
arch/alpha/kernel/sys_jensen.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/sys_mikasa.c
arch/alpha/kernel/sys_noritake.c
arch/alpha/kernel/sys_rawhide.c
arch/alpha/kernel/sys_rx164.c
arch/alpha/kernel/sys_sable.c
arch/alpha/kernel/sys_takara.c
arch/alpha/kernel/sys_titan.c
arch/alpha/kernel/sys_wildfire.c
arch/arm/Kconfig
arch/arm/kernel/Makefile
arch/arm/kernel/armksyms.c
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/bios32.c
arch/arm/kernel/crunch-bits.S [new file with mode: 0644]
arch/arm/kernel/crunch.c [new file with mode: 0644]
arch/arm/kernel/entry-armv.S
arch/arm/kernel/ptrace.c
arch/arm/kernel/setup.c
arch/arm/kernel/signal.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/lib/Makefile
arch/arm/lib/backtrace.S
arch/arm/lib/clear_user.S
arch/arm/lib/copy_from_user.S
arch/arm/lib/copy_to_user.S
arch/arm/lib/strncpy_from_user.S
arch/arm/lib/strnlen_user.S
arch/arm/lib/uaccess.S
arch/arm/mach-ep93xx/Kconfig
arch/arm/mach-ep93xx/Makefile
arch/arm/mach-ep93xx/edb9315.c [new file with mode: 0644]
arch/arm/mach-ep93xx/gesbc9312.c
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-ixp23xx/espresso.c
arch/arm/mach-ixp23xx/ixdp2351.c
arch/arm/mach-ixp23xx/roadrunner.c
arch/arm/mach-pxa/irq.c
arch/arm/mach-s3c2410/s3c244x.c
arch/arm/mm/Kconfig
arch/arm/mm/Makefile
arch/arm/mm/init.c
arch/arm/mm/iomap.c [new file with mode: 0644]
arch/arm/mm/ioremap.c
arch/arm/mm/nommu.c [new file with mode: 0644]
arch/arm/mm/proc-arm1020.S
arch/arm/mm/proc-arm1020e.S
arch/arm/mm/proc-arm1022.S
arch/arm/mm/proc-arm1026.S
arch/arm/mm/proc-arm6_7.S
arch/arm/mm/proc-arm720.S
arch/arm/mm/proc-arm920.S
arch/arm/mm/proc-arm922.S
arch/arm/mm/proc-arm925.S
arch/arm/mm/proc-arm926.S
arch/arm/mm/proc-sa110.S
arch/arm/mm/proc-sa1100.S
arch/arm/mm/proc-v6.S
arch/cris/Kconfig
arch/cris/arch-v10/kernel/debugport.c
arch/cris/arch-v10/kernel/irq.c
arch/cris/arch-v32/drivers/pci/bios.c
arch/cris/arch-v32/kernel/debugport.c
arch/cris/arch-v32/kernel/irq.c
arch/cris/kernel/irq.c
arch/frv/mb93090-mb00/pci-frv.c
arch/i386/Kconfig
arch/i386/kernel/asm-offsets.c
arch/i386/kernel/cpu/amd.c
arch/i386/kernel/cpu/common.c
arch/i386/kernel/cpu/intel_cacheinfo.c
arch/i386/kernel/cpu/proc.c
arch/i386/kernel/cpuid.c
arch/i386/kernel/efi.c
arch/i386/kernel/entry.S
arch/i386/kernel/i8259.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.c
arch/i386/kernel/microcode.c
arch/i386/kernel/msr.c
arch/i386/kernel/scx200.c
arch/i386/kernel/setup.c
arch/i386/kernel/signal.c
arch/i386/kernel/smpboot.c
arch/i386/kernel/sysenter.c
arch/i386/kernel/topology.c
arch/i386/kernel/vsyscall-sysenter.S
arch/i386/kernel/vsyscall.lds.S
arch/i386/mach-visws/setup.c
arch/i386/mach-visws/visws_apic.c
arch/i386/mach-voyager/setup.c
arch/i386/mach-voyager/voyager_smp.c
arch/i386/mm/init.c
arch/i386/mm/pageattr.c
arch/i386/pci/i386.c
arch/ia64/Kconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/hp/sim/hpsim_irq.c
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/irq.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/irq_lsapic.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/palinfo.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/topology.c
arch/ia64/mm/discontig.c
arch/ia64/mm/init.c
arch/ia64/pci/pci.c
arch/ia64/sn/kernel/irq.c
arch/ia64/sn/kernel/setup.c
arch/ia64/sn/pci/tioca_provider.c
arch/m32r/kernel/irq.c
arch/m32r/kernel/setup.c
arch/m32r/kernel/setup_m32104ut.c
arch/m32r/kernel/setup_m32700ut.c
arch/m32r/kernel/setup_mappi.c
arch/m32r/kernel/setup_mappi2.c
arch/m32r/kernel/setup_mappi3.c
arch/m32r/kernel/setup_oaks32r.c
arch/m32r/kernel/setup_opsput.c
arch/m32r/kernel/setup_usrv.c
arch/m68knommu/Kconfig
arch/m68knommu/Makefile
arch/m68knommu/defconfig
arch/m68knommu/kernel/comempci.c
arch/m68knommu/kernel/vmlinux.lds.S
arch/m68knommu/platform/68328/Makefile
arch/m68knommu/platform/68328/head-rom.S
arch/m68knommu/platform/68328/ints.c
arch/m68knommu/platform/68328/romvec.S [new file with mode: 0644]
arch/m68knommu/platform/68360/config.c
arch/m68knommu/platform/68360/head-ram.S
arch/m68knommu/platform/68360/head-rom.S
arch/m68knommu/platform/68360/ints.c
arch/m68knommu/platform/68EZ328/config.c
arch/m68knommu/platform/68VZ328/config.c
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/au1000/common/dbdma.c
arch/mips/au1000/common/irq.c
arch/mips/au1000/common/power.c
arch/mips/au1000/csb250/init.c
arch/mips/au1000/pb1200/irqmap.c
arch/mips/basler/excite/excite_setup.c
arch/mips/ddb5xxx/common/prom.c
arch/mips/ddb5xxx/ddb5477/irq_5477.c
arch/mips/dec/ioasic-irq.c
arch/mips/dec/kn02-irq.c
arch/mips/gt64120/common/Makefile
arch/mips/gt64120/common/pci.c [deleted file]
arch/mips/gt64120/ev64120/irq.c
arch/mips/gt64120/momenco_ocelot/setup.c
arch/mips/gt64120/wrppmc/Makefile
arch/mips/gt64120/wrppmc/int-handler.S [deleted file]
arch/mips/gt64120/wrppmc/irq.c
arch/mips/gt64120/wrppmc/setup.c
arch/mips/gt64120/wrppmc/time.c
arch/mips/ite-boards/generic/irq.c
arch/mips/jazz/irq.c
arch/mips/jmr3927/rbhma3100/irq.c
arch/mips/kernel/apm.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/entry.S
arch/mips/kernel/gdb-low.S
arch/mips/kernel/genex.S
arch/mips/kernel/head.S
arch/mips/kernel/i8259.c
arch/mips/kernel/irq-msc01.c
arch/mips/kernel/irq-mv6434x.c
arch/mips/kernel/irq-rm7000.c
arch/mips/kernel/irq-rm9000.c
arch/mips/kernel/irq.c
arch/mips/kernel/irq_cpu.c
arch/mips/kernel/r4k_switch.S
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/setup.c
arch/mips/kernel/smp.c
arch/mips/kernel/smtc-asm.S
arch/mips/kernel/smtc.c
arch/mips/kernel/syscall.c
arch/mips/kernel/traps.c
arch/mips/lasat/interrupt.c
arch/mips/mips-boards/atlas/atlas_int.c
arch/mips/mm/Makefile
arch/mips/mm/c-r4k.c
arch/mips/mm/sc-mips.c [new file with mode: 0644]
arch/mips/momentum/jaguar_atx/setup.c
arch/mips/momentum/ocelot_c/cpci-irq.c
arch/mips/momentum/ocelot_c/setup.c
arch/mips/momentum/ocelot_c/uart-irq.c
arch/mips/momentum/ocelot_g/setup.c
arch/mips/oprofile/op_model_mipsxx.c
arch/mips/pci/Makefile
arch/mips/pci/ops-tx4927.c
arch/mips/pci/ops-tx4938.c
arch/mips/pci/pci.c
arch/mips/philips/pnx8550/common/int.c
arch/mips/pmc-sierra/yosemite/ht.c
arch/mips/sgi-ip22/ip22-eisa.c
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip27/Kconfig
arch/mips/sgi-ip27/Makefile
arch/mips/sgi-ip27/ip27-console.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sibyte/Kconfig
arch/mips/sibyte/bcm1480/irq.c
arch/mips/sibyte/sb1250/irq.c
arch/mips/sni/irq.c
arch/mips/tx4927/common/tx4927_irq.c
arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
arch/mips/tx4938/common/irq.c
arch/mips/tx4938/toshiba_rbtx4938/irq.c
arch/mips/vr41xx/common/icu.c
arch/mips/vr41xx/common/irq.c
arch/mips/vr41xx/common/vrc4173.c
arch/mips/vr41xx/nec-cmbvr4133/irq.c
arch/parisc/Kconfig
arch/parisc/kernel/cache.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/firmware.c
arch/parisc/kernel/irq.c
arch/parisc/kernel/module.c
arch/parisc/kernel/pci.c
arch/parisc/kernel/pdc_chassis.c
arch/parisc/kernel/ptrace.c
arch/parisc/kernel/real2.S
arch/parisc/kernel/setup.c
arch/parisc/kernel/signal.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/time.c
arch/parisc/kernel/topology.c
arch/parisc/kernel/traps.c
arch/parisc/kernel/unaligned.c
arch/powerpc/Kconfig
arch/powerpc/Kconfig.debug
arch/powerpc/configs/cell_defconfig
arch/powerpc/configs/mpc7448_hpc2_defconfig [new file with mode: 0644]
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/cpu_setup_power4.S
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/crash.c
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/legacy_serial.c
arch/powerpc/kernel/lparcfg.c
arch/powerpc/kernel/machine_kexec_64.c
arch/powerpc/kernel/misc.S [new file with mode: 0644]
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/udbg.c
arch/powerpc/mm/hash_native_64.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/mmu_context_64.c
arch/powerpc/mm/numa.c
arch/powerpc/platforms/83xx/pci.c
arch/powerpc/platforms/85xx/pci.c
arch/powerpc/platforms/86xx/Kconfig
arch/powerpc/platforms/86xx/Makefile
arch/powerpc/platforms/86xx/mpc8641_hpcn.h
arch/powerpc/platforms/86xx/mpc86xx.h
arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
arch/powerpc/platforms/86xx/mpc86xx_smp.c
arch/powerpc/platforms/86xx/pci.c
arch/powerpc/platforms/Makefile
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/cell/setup.c
arch/powerpc/platforms/cell/spider-pic.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/switch.c
arch/powerpc/platforms/chrp/pci.c
arch/powerpc/platforms/embedded6xx/Kconfig
arch/powerpc/platforms/embedded6xx/Makefile [new file with mode: 0644]
arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c [new file with mode: 0644]
arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h [new file with mode: 0644]
arch/powerpc/platforms/iseries/dt.c
arch/powerpc/platforms/iseries/htab.c
arch/powerpc/platforms/iseries/irq.c
arch/powerpc/platforms/iseries/lpevents.c
arch/powerpc/platforms/iseries/proc.c
arch/powerpc/platforms/iseries/setup.c
arch/powerpc/platforms/maple/pci.c
arch/powerpc/platforms/maple/setup.c
arch/powerpc/platforms/powermac/backlight.c
arch/powerpc/platforms/powermac/pci.c
arch/powerpc/platforms/powermac/pfunc_core.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/pseries/eeh_event.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/xics.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/dart.h
arch/powerpc/sysdev/dart_iommu.c
arch/powerpc/sysdev/i8259.c
arch/powerpc/sysdev/ipic.c
arch/powerpc/sysdev/mmio_nvram.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/todc.c [new file with mode: 0644]
arch/powerpc/sysdev/tsi108_dev.c [new file with mode: 0644]
arch/powerpc/sysdev/tsi108_pci.c [new file with mode: 0644]
arch/ppc/4xx_io/serial_sicc.c
arch/ppc/8xx_io/commproc.c
arch/ppc/Kconfig
arch/ppc/kernel/pci.c
arch/ppc/kernel/setup.c
arch/ppc/platforms/apus_setup.c
arch/ppc/platforms/sbc82xx.c
arch/ppc/syslib/cpc700_pic.c
arch/ppc/syslib/cpm2_pic.c
arch/ppc/syslib/gt64260_pic.c
arch/ppc/syslib/m82xx_pci.c
arch/ppc/syslib/m8xx_setup.c
arch/ppc/syslib/mpc52xx_pic.c
arch/ppc/syslib/mv64360_pic.c
arch/ppc/syslib/open_pic.c
arch/ppc/syslib/open_pic2.c
arch/ppc/syslib/ppc403_pic.c
arch/ppc/syslib/ppc4xx_pic.c
arch/ppc/syslib/xilinx_pic.c
arch/s390/appldata/appldata.h
arch/s390/appldata/appldata_base.c
arch/s390/appldata/appldata_mem.c
arch/s390/appldata/appldata_net_sum.c
arch/s390/appldata/appldata_os.c
arch/s390/kernel/binfmt_elf32.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/head.S
arch/s390/kernel/head31.S
arch/s390/kernel/head64.S
arch/s390/kernel/s390_ksyms.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/traps.c
arch/sh/Kconfig
arch/sh/boards/adx/irq_maskreg.c
arch/sh/boards/bigsur/irq.c
arch/sh/boards/cqreek/irq.c
arch/sh/boards/dreamcast/setup.c
arch/sh/boards/ec3104/setup.c
arch/sh/boards/harp/irq.c
arch/sh/boards/mpc1211/pci.c
arch/sh/boards/mpc1211/setup.c
arch/sh/boards/overdrive/galileo.c
arch/sh/boards/overdrive/irq.c
arch/sh/boards/renesas/hs7751rvoip/irq.c
arch/sh/boards/renesas/rts7751r2d/irq.c
arch/sh/boards/renesas/systemh/irq.c
arch/sh/boards/se/73180/irq.c
arch/sh/boards/superh/microdev/irq.c
arch/sh/cchips/hd6446x/hd64461/setup.c
arch/sh/cchips/hd6446x/hd64465/setup.c
arch/sh/cchips/voyagergx/irq.c
arch/sh/drivers/pci/pci.c
arch/sh/kernel/cpu/irq/imask.c
arch/sh/kernel/cpu/irq/intc2.c
arch/sh/kernel/cpu/irq/ipr.c
arch/sh/kernel/cpu/irq/pint.c
arch/sh/kernel/cpu/sh4/sq.c
arch/sh/kernel/irq.c
arch/sh/kernel/setup.c
arch/sh64/kernel/irq.c
arch/sh64/kernel/irq_intc.c
arch/sh64/kernel/pcibios.c
arch/sh64/kernel/setup.c
arch/sh64/mach-cayman/irq.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/setup.c
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/setup.c
arch/sparc64/mm/init.c
arch/sparc64/solaris/socksys.c
arch/um/drivers/line.c
arch/um/drivers/ssl.c
arch/um/drivers/stdio_console.c
arch/um/drivers/ubd_kern.c
arch/um/include/line.h
arch/um/kernel/irq.c
arch/v850/kernel/irq.c
arch/v850/kernel/rte_mb_a_pci.c
arch/x86_64/Kconfig
arch/x86_64/kernel/entry.S
arch/x86_64/kernel/i8259.c
arch/x86_64/kernel/io_apic.c
arch/x86_64/kernel/irq.c
arch/x86_64/kernel/mce.c
arch/x86_64/kernel/nmi.c
arch/x86_64/kernel/smp.c
arch/x86_64/kernel/smpboot.c
arch/x86_64/mm/init.c
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/pci.c
arch/xtensa/kernel/time.c
arch/xtensa/kernel/traps.c
block/ll_rw_blk.c
drivers/acpi/Kconfig
drivers/acpi/acpi_memhotplug.c
drivers/acpi/numa.c
drivers/amba/bus.c
drivers/atm/ambassador.c
drivers/atm/firestream.c
drivers/base/cpu.c
drivers/base/dmapool.c
drivers/base/memory.c
drivers/base/node.c
drivers/base/topology.c
drivers/block/DAC960.c
drivers/block/acsi.c
drivers/block/acsi_slm.c
drivers/block/cciss.c
drivers/block/cpqarray.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/paride/pf.c
drivers/block/paride/pg.c
drivers/block/paride/pt.c
drivers/block/pktcdvd.c
drivers/block/ps2esdi.c
drivers/block/rd.c
drivers/block/swim3.c
drivers/block/sx8.c
drivers/block/ub.c
drivers/block/umem.c
drivers/block/viodasd.c
drivers/block/xd.c
drivers/block/z2ram.c
drivers/cdrom/aztcd.c
drivers/cdrom/cdu31a.c
drivers/cdrom/cm206.c
drivers/cdrom/gscd.c
drivers/cdrom/mcdx.c
drivers/cdrom/optcd.c
drivers/cdrom/sbpcd.c
drivers/cdrom/sjcd.c
drivers/cdrom/sonycd535.c
drivers/cdrom/viocd.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/agp/Kconfig
drivers/char/agp/amd64-agp.c
drivers/char/agp/ati-agp.c
drivers/char/agp/nvidia-agp.c
drivers/char/agp/sgi-agp.c
drivers/char/applicom.c
drivers/char/cyclades.c
drivers/char/drm/drm_memory_debug.h
drivers/char/drm/via_dmablit.c
drivers/char/dsp56k.c
drivers/char/dtlk.c
drivers/char/epca.c
drivers/char/esp.c
drivers/char/ftape/zftape/zftape-init.c
drivers/char/hvc_console.c
drivers/char/hvcs.c
drivers/char/hvsi.c
drivers/char/ip2/ip2main.c
drivers/char/ipmi/ipmi_devintf.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_watchdog.c
drivers/char/isicom.c
drivers/char/istallion.c
drivers/char/lp.c
drivers/char/mem.c
drivers/char/misc.c
drivers/char/mmtimer.c
drivers/char/moxa.c
drivers/char/mxser.c
drivers/char/n_tty.c
drivers/char/nsc_gpio.c [new file with mode: 0644]
drivers/char/pc8736x_gpio.c [new file with mode: 0644]
drivers/char/ppdev.c
drivers/char/pty.c
drivers/char/raw.c
drivers/char/riscom8.c
drivers/char/rocket.c
drivers/char/scx200_gpio.c
drivers/char/serial167.c
drivers/char/specialix.c
drivers/char/stallion.c
drivers/char/sx.c
drivers/char/tipar.c
drivers/char/tty_io.c
drivers/char/vc_screen.c
drivers/char/viocons.c
drivers/char/viotape.c
drivers/char/vme_scc.c
drivers/char/vr41xx_giu.c
drivers/char/vt.c
drivers/char/watchdog/at91_wdt.c
drivers/char/watchdog/i8xx_tco.c
drivers/char/watchdog/pcwd_pci.c
drivers/char/watchdog/pcwd_usb.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/i2c/busses/i2c-i801.c
drivers/ide/Kconfig
drivers/ide/ide-cd.c
drivers/ide/ide-disk.c
drivers/ide/ide-floppy.c
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/ide-probe.c
drivers/ide/ide-tape.c
drivers/ide/ide.c
drivers/ide/pci/aec62xx.c
drivers/ide/pci/amd74xx.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/hpt34x.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/sc1200.c
drivers/ide/pci/serverworks.c
drivers/ide/pci/siimage.c
drivers/ide/pci/sl82c105.c
drivers/ide/pci/slc90e66.c
drivers/ide/ppc/pmac.c
drivers/ieee1394/ohci1394.c
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/input/input.c
drivers/input/joystick/db9.c
drivers/input/keyboard/atkbd.c
drivers/input/misc/wistron_btns.c
drivers/input/serio/ct82c710.c
drivers/input/serio/serio_raw.c
drivers/isdn/capi/capi.c
drivers/isdn/gigaset/bas-gigaset.c
drivers/isdn/gigaset/common.c
drivers/isdn/gigaset/gigaset.h
drivers/isdn/gigaset/interface.c
drivers/isdn/gigaset/usb-gigaset.c
drivers/isdn/hardware/avm/b1pcmcia.c
drivers/isdn/hardware/eicon/divamnt.c
drivers/isdn/hardware/eicon/divasi.c
drivers/isdn/hardware/eicon/divasmain.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/sedlbauer_cs.c
drivers/isdn/hisax/teles3.c
drivers/isdn/hisax/telespci.c
drivers/isdn/i4l/isdn_common.c
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/i4l/isdn_x25iface.c
drivers/leds/led-core.c
drivers/leds/led-triggers.c
drivers/macintosh/Kconfig
drivers/macintosh/Makefile
drivers/macintosh/adb.c
drivers/macintosh/macio_asic.c
drivers/macintosh/via-pmu-led.c [new file with mode: 0644]
drivers/md/dm-ioctl.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/raid5.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/radio/miropcm20-rds.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/arv.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/cx2341x.c
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/pvrusb2/Kconfig [new file with mode: 0644]
drivers/media/video/pvrusb2/Makefile [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-audio.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-audio.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-context.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-context.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-ctrl.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-ctrl.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-debug.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-debugifc.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-debugifc.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-demod.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-demod.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-eeprom.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-eeprom.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-encoder.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-encoder.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-hdw.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-hdw.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-i2c-core.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-io.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-io.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-ioread.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-ioread.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-main.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-std.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-std.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-sysfs.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-sysfs.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-tuner.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-tuner.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-util.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-v4l2.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-v4l2.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-video-v4l.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-video-v4l.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-wm8775.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-wm8775.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2.h [new file with mode: 0644]
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/stradis.c
drivers/media/video/tda9887.c
drivers/media/video/tuner-core.c
drivers/media/video/v4l2-common.c
drivers/media/video/videodev.c
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptsas.c
drivers/message/i2o/i2o_block.c
drivers/message/i2o/iop.c
drivers/misc/ibmasm/module.c
drivers/mmc/mmc_block.c
drivers/mmc/mmci.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/jedec.c
drivers/mtd/chips/map_absent.c
drivers/mtd/chips/map_ram.c
drivers/mtd/chips/map_rom.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/ms02-nv.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/phram.c
drivers/mtd/devices/pmc551.c
drivers/mtd/devices/slram.c
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/ichxrom.c
drivers/mtd/maps/ixp2000.c
drivers/mtd/maps/physmap.c
drivers/mtd/maps/scx200_docflash.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/mtdchar.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/ndfc.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/ts7250.c
drivers/net/3c59x.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/dl2k.h
drivers/net/dm9000.c
drivers/net/e100.c
drivers/net/eepro100.c
drivers/net/epic100.c
drivers/net/fealnx.c
drivers/net/fec.c
drivers/net/fs_enet/fs_enet-mii.c
drivers/net/hamradio/dmascc.c
drivers/net/natsemi.c
drivers/net/pcnet32.c
drivers/net/phy/lxt.c
drivers/net/ppp_generic.c
drivers/net/skge.c
drivers/net/sky2.c
drivers/net/tulip/de2104x.c
drivers/net/tulip/tulip_core.c
drivers/net/tulip/winbond-840.c
drivers/net/tun.c
drivers/net/typhoon.c
drivers/net/wan/c101.c
drivers/net/wan/cosa.c
drivers/net/wan/dscc4.c
drivers/net/wan/n2.c
drivers/net/wan/pc300_drv.c
drivers/net/wan/pci200syn.c
drivers/net/wireless/ipw2200.c
drivers/net/yellowfin.c
drivers/parisc/Kconfig
drivers/parisc/dino.c
drivers/parisc/eisa.c
drivers/parisc/gsc.c
drivers/parisc/iosapic.c
drivers/parisc/pdc_stable.c
drivers/parisc/sba_iommu.c
drivers/parisc/superio.c
drivers/pci/bus.c
drivers/pci/hotplug/cpcihp_zt5550.c
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/shpchp_sysfs.c
drivers/pci/msi.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/proc.c
drivers/pci/rom.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/pcmcia/hd64465_ss.c
drivers/pcmcia/i82365.c
drivers/pcmcia/m8xx_pcmcia.c
drivers/pcmcia/pd6729.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/tcic.c
drivers/pnp/interface.c
drivers/pnp/manager.c
drivers/pnp/resource.c
drivers/rapidio/rio-access.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/class.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-rs5c348.c [new file with mode: 0644]
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-vr41xx.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3370_erp.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_9336_erp.c
drivers/s390/block/dasd_9343_erp.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_diag.h
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eckd.h
drivers/s390/block/dasd_eer.c
drivers/s390/block/dasd_erp.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_fba.h
drivers/s390/block/dasd_genhd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/block/xpram.c
drivers/s390/char/monreader.c
drivers/s390/char/raw3270.c
drivers/s390/char/tty3270.c
drivers/s390/cio/blacklist.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/cmf.c
drivers/s390/cio/css.c
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/crypto/z90main.c
drivers/s390/s390mach.c
drivers/sbus/char/bpp.c
drivers/sbus/char/vfc.h
drivers/sbus/char/vfc_dev.c
drivers/scsi/Kconfig
drivers/scsi/ahci.c
drivers/scsi/ata_piix.c
drivers/scsi/libata-core.c
drivers/scsi/libata-eh.c
drivers/scsi/libata-scsi.c
drivers/scsi/libata.h
drivers/scsi/sata_nv.c
drivers/scsi/sata_sil.c
drivers/scsi/sata_sil24.c
drivers/scsi/sata_svw.c
drivers/scsi/sata_uli.c
drivers/scsi/sata_via.c
drivers/scsi/sata_vsc.c
drivers/serial/21285.c
drivers/serial/68328serial.c
drivers/serial/8250.c
drivers/serial/8250_pci.c
drivers/serial/at91_serial.c
drivers/serial/crisv10.c
drivers/serial/dz.c
drivers/serial/imx.c
drivers/serial/ip22zilog.c
drivers/serial/jsm/jsm_tty.c
drivers/serial/m32r_sio.c
drivers/serial/mcfserial.c
drivers/serial/mpc52xx_uart.c
drivers/serial/mpsc.c
drivers/serial/pmac_zilog.c
drivers/serial/pxa.c
drivers/serial/s3c2410.c
drivers/serial/sa1100.c
drivers/serial/serial_core.c
drivers/serial/serial_txx9.c
drivers/serial/sh-sci.c
drivers/serial/sunhv.c
drivers/serial/sunsab.c
drivers/serial/sunsu.c
drivers/serial/sunzilog.c
drivers/serial/v850e_uart.c
drivers/serial/vr41xx_siu.c
drivers/sn/ioc3.c
drivers/sn/ioc4.c
drivers/spi/spi.c
drivers/tc/zs.c
drivers/telephony/phonedev.c
drivers/usb/class/cdc-acm.c
drivers/usb/gadget/pxa2xx_udc.c
drivers/usb/gadget/serial.c
drivers/usb/host/sl811-hcd.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/usb-serial.c
drivers/video/aty/radeon_backlight.c
drivers/video/au1100fb.c
drivers/video/backlight/hp680_bl.c
drivers/video/console/vgacon.c
drivers/video/fbmem.c
drivers/video/sgivwfb.c
fs/9p/mux.c
fs/9p/v9fs_vfs.h
fs/9p/vfs_addr.c
fs/9p/vfs_inode.c
fs/Kconfig
fs/Makefile
fs/adfs/inode.c
fs/affs/affs.h
fs/affs/file.c
fs/affs/symlink.c
fs/afs/file.c
fs/afs/internal.h
fs/befs/linuxvfs.c
fs/bfs/bfs.h
fs/bfs/file.c
fs/block_dev.c
fs/buffer.c
fs/char_dev.c
fs/cifs/CHANGES
fs/cifs/Makefile
fs/cifs/README
fs/cifs/asn1.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_debug.h
fs/cifs/cifs_unicode.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/fcntl.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/misc.c
fs/cifs/netmisc.c
fs/cifs/ntlmssp.c [deleted file]
fs/cifs/readdir.c
fs/cifs/sess.c [new file with mode: 0644]
fs/cifs/smbencrypt.c
fs/cifs/transport.c
fs/coda/psdev.c
fs/coda/symlink.c
fs/compat_ioctl.c
fs/configfs/inode.c
fs/cramfs/inode.c
fs/devfs/Makefile [deleted file]
fs/devfs/base.c [deleted file]
fs/devfs/util.c [deleted file]
fs/efs/inode.c
fs/efs/symlink.c
fs/ext2/ext2.h
fs/ext2/inode.c
fs/ext3/inode.c
fs/fat/inode.c
fs/freevxfs/vxfs_immed.c
fs/freevxfs/vxfs_inode.c
fs/freevxfs/vxfs_subr.c
fs/fuse/file.c
fs/hfs/hfs_fs.h
fs/hfs/inode.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/inode.c
fs/hostfs/hostfs_kern.c
fs/hpfs/file.c
fs/hpfs/hpfs_fn.h
fs/hpfs/namei.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/isofs/compress.c
fs/isofs/inode.c
fs/isofs/isofs.h
fs/isofs/rock.c
fs/isofs/zisofs.h
fs/jbd/journal.c
fs/jffs/inode-v23.c
fs/jffs2/acl.c
fs/jffs2/erase.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/gc.c
fs/jffs2/jffs2_fs_sb.h
fs/jffs2/malloc.c
fs/jffs2/nodelist.c
fs/jffs2/nodemgmt.c
fs/jffs2/os-linux.h
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/summary.c
fs/jffs2/xattr.c
fs/jffs2/xattr.h
fs/jfs/inode.c
fs/jfs/jfs_inode.h
fs/jfs/jfs_metapage.c
fs/jfs/jfs_metapage.h
fs/minix/inode.c
fs/ncpfs/inode.c
fs/ncpfs/symlink.c
fs/nfs/direct.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/pagelist.c
fs/nfs/read.c
fs/nfs/write.c
fs/nfsd/nfs4state.c
fs/ntfs/aops.c
fs/ntfs/ntfs.h
fs/ocfs2/aops.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmlock.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/dlmglue.c
fs/ocfs2/inode.h
fs/ocfs2/journal.c
fs/ocfs2/vote.c
fs/partitions/Makefile
fs/partitions/check.c
fs/partitions/devfs.c [deleted file]
fs/partitions/devfs.h [deleted file]
fs/proc/task_mmu.c
fs/qnx4/inode.c
fs/ramfs/file-mmu.c
fs/ramfs/file-nommu.c
fs/ramfs/internal.h
fs/reiserfs/inode.c
fs/romfs/inode.c
fs/smbfs/file.c
fs/smbfs/proto.h
fs/sysfs/inode.c
fs/sysv/itree.c
fs/sysv/sysv.h
fs/udf/file.c
fs/udf/inode.c
fs/udf/symlink.c
fs/udf/udfdecl.h
fs/ufs/inode.c
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_aops.h
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/linux-2.6/xfs_vnode.h
fs/xfs/xfs_behavior.h
fs/xfs/xfs_inode.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_vnodeops.c
include/asm-alpha/core_t2.h
include/asm-alpha/hw_irq.h
include/asm-arm/arch-at91rm9200/memory.h
include/asm-arm/arch-h720x/memory.h
include/asm-arm/arch-imx/memory.h
include/asm-arm/arch-ixp23xx/ixp23xx.h
include/asm-arm/arch-ixp23xx/platform.h
include/asm-arm/arch-ixp23xx/uncompress.h
include/asm-arm/arch-s3c2410/regs-dsc.h
include/asm-arm/arch-s3c2410/regs-nand.h
include/asm-arm/bugs.h
include/asm-arm/domain.h
include/asm-arm/fpstate.h
include/asm-arm/mach/map.h
include/asm-arm/mach/pci.h
include/asm-arm/memory.h
include/asm-arm/mmu.h
include/asm-arm/mmu_context.h
include/asm-arm/page-nommu.h [new file with mode: 0644]
include/asm-arm/page.h
include/asm-arm/pgalloc.h
include/asm-arm/pgtable-nommu.h [new file with mode: 0644]
include/asm-arm/pgtable.h
include/asm-arm/proc-fns.h
include/asm-arm/ptrace.h
include/asm-arm/thread_info.h
include/asm-arm/uaccess.h
include/asm-arm/ucontext.h
include/asm-cris/hw_irq.h
include/asm-cris/irq.h
include/asm-generic/bug.h
include/asm-generic/vmlinux.lds.h
include/asm-i386/cpu.h
include/asm-i386/elf.h
include/asm-i386/fixmap.h
include/asm-i386/hw_irq.h
include/asm-i386/mach-visws/setup_arch.h
include/asm-i386/mmu.h
include/asm-i386/node.h [deleted file]
include/asm-i386/page.h
include/asm-i386/processor.h
include/asm-i386/thread_info.h
include/asm-i386/topology.h
include/asm-i386/unwind.h
include/asm-ia64/hw_irq.h
include/asm-ia64/irq.h
include/asm-ia64/nodedata.h
include/asm-ia64/sn/sn_sal.h
include/asm-ia64/topology.h
include/asm-m32r/hw_irq.h
include/asm-m68knommu/bootstd.h
include/asm-m68knommu/ptrace.h
include/asm-mips/asmmacro.h
include/asm-mips/cpu-features.h
include/asm-mips/fixmap.h
include/asm-mips/hazards.h
include/asm-mips/hw_irq.h
include/asm-mips/irq.h
include/asm-mips/mach-au1x00/au1xxx_psc.h
include/asm-mips/mach-mips/irq.h
include/asm-mips/mipsregs.h
include/asm-mips/sn/ioc3.h
include/asm-mips/sn/klconfig.h
include/asm-mips/stackframe.h
include/asm-mips/unistd.h
include/asm-parisc/assembly.h
include/asm-parisc/compat.h
include/asm-parisc/hw_irq.h
include/asm-parisc/irq.h
include/asm-parisc/pdc.h
include/asm-parisc/pgtable.h
include/asm-parisc/processor.h
include/asm-parisc/system.h
include/asm-parisc/uaccess.h
include/asm-parisc/unistd.h
include/asm-powerpc/cputable.h
include/asm-powerpc/hw_irq.h
include/asm-powerpc/irq.h
include/asm-powerpc/iseries/it_lp_queue.h
include/asm-powerpc/kdump.h
include/asm-powerpc/kexec.h
include/asm-powerpc/machdep.h
include/asm-powerpc/mmu.h
include/asm-powerpc/mmu_context.h
include/asm-powerpc/mpc86xx.h
include/asm-powerpc/pci.h
include/asm-powerpc/rtas.h
include/asm-powerpc/time.h
include/asm-powerpc/todc.h [new file with mode: 0644]
include/asm-powerpc/topology.h
include/asm-powerpc/tsi108.h [new file with mode: 0644]
include/asm-powerpc/udbg.h
include/asm-ppc/ocp.h
include/asm-ppc/pci.h
include/asm-s390/bitops.h
include/asm-s390/cio.h
include/asm-s390/cmb.h
include/asm-s390/dasd.h
include/asm-s390/thread_info.h
include/asm-s390/unistd.h
include/asm-sh/hw_irq.h
include/asm-sh64/hw_irq.h
include/asm-sparc64/topology.h
include/asm-um/hw_irq.h
include/asm-v850/hw_irq.h
include/asm-x86_64/hw_irq.h
include/asm-x86_64/topology.h
include/asm-xtensa/hw_irq.h
include/linux/ac97_codec.h
include/linux/acpi.h
include/linux/buffer_head.h
include/linux/coda_linux.h
include/linux/compat_ioctl.h
include/linux/cpu.h
include/linux/devfs_fs.h [deleted file]
include/linux/devfs_fs_kernel.h [deleted file]
include/linux/dmaengine.h
include/linux/efs_fs.h
include/linux/elf-em.h
include/linux/fb.h
include/linux/fs.h
include/linux/futex.h
include/linux/genhd.h
include/linux/ide.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/ioport.h
include/linux/ipmi.h
include/linux/irq.h
include/linux/isdn/tpam.h [deleted file]
include/linux/jffs2.h
include/linux/kbd_kern.h
include/linux/key.h
include/linux/libata.h
include/linux/list.h
include/linux/memory_hotplug.h
include/linux/miscdevice.h
include/linux/mm.h
include/linux/module.h
include/linux/nfs_fs.h
include/linux/node.h
include/linux/nsc_gpio.h [new file with mode: 0644]
include/linux/pci.h
include/linux/pci_ids.h
include/linux/plist.h [new file with mode: 0644]
include/linux/pnp.h
include/linux/poison.h [new file with mode: 0644]
include/linux/rcupdate.h
include/linux/reiserfs_fs.h
include/linux/rtmutex.h [new file with mode: 0644]
include/linux/sched.h
include/linux/scx200.h
include/linux/scx200_gpio.h
include/linux/serial_core.h
include/linux/spi/spi.h
include/linux/swap.h
include/linux/syscalls.h
include/linux/sysctl.h
include/linux/topology.h
include/linux/tty.h
include/linux/tty_driver.h
include/linux/tty_flip.h
include/linux/types.h
include/linux/ufs_fs.h
include/linux/watchdog.h
include/media/cx2341x.h
include/media/v4l2-dev.h
include/sound/ac97_codec.h
include/sound/ak4xxx-adda.h
include/sound/initval.h
init/Kconfig
init/Makefile
init/do_mounts.c
init/do_mounts.h
init/do_mounts_devfs.c [deleted file]
init/do_mounts_initrd.c
init/do_mounts_md.c
init/do_mounts_rd.c
init/main.c
kernel/Makefile
kernel/acct.c
kernel/audit.c
kernel/auditsc.c
kernel/cpu.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/futex_compat.c
kernel/hrtimer.c
kernel/irq/Makefile
kernel/irq/autoprobe.c
kernel/irq/chip.c [new file with mode: 0644]
kernel/irq/handle.c
kernel/irq/internals.h
kernel/irq/manage.c
kernel/irq/migration.c
kernel/irq/proc.c
kernel/irq/resend.c [new file with mode: 0644]
kernel/irq/spurious.c
kernel/kexec.c
kernel/module.c
kernel/mutex-debug.c
kernel/power/Kconfig
kernel/profile.c
kernel/rcupdate.c
kernel/rcutorture.c
kernel/resource.c
kernel/rtmutex-debug.c [new file with mode: 0644]
kernel/rtmutex-debug.h [new file with mode: 0644]
kernel/rtmutex-tester.c [new file with mode: 0644]
kernel/rtmutex.c [new file with mode: 0644]
kernel/rtmutex.h [new file with mode: 0644]
kernel/rtmutex_common.h [new file with mode: 0644]
kernel/sched.c
kernel/softirq.c
kernel/softlockup.c
kernel/sysctl.c
kernel/timer.c
kernel/workqueue.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/plist.c [new file with mode: 0644]
lib/vsprintf.c
lib/zlib_inflate/inffast.c
lib/zlib_inflate/inftrees.c
mm/Kconfig
mm/filemap.c
mm/filemap.h
mm/filemap_xip.c
mm/memory_hotplug.c
mm/page-writeback.c
mm/page_alloc.c
mm/shmem.c
mm/slab.c
mm/sparse.c
mm/swap_state.c
mm/tiny-shmem.c
mm/vmscan.c
net/bluetooth/rfcomm/tty.c
net/ipv6/route.c
net/irda/ircomm/ircomm_tty.c
net/irda/irnet/irnet.h
net/sunrpc/auth_gss/gss_krb5_seal.c
net/tipc/bcast.c
net/tipc/bearer.c
net/tipc/config.c
net/tipc/dbg.c
net/tipc/handler.c
net/tipc/name_table.c
net/tipc/net.c
net/tipc/node.c
net/tipc/port.c
net/tipc/ref.c
net/tipc/subscr.c
net/tipc/user_reg.c
scripts/Kbuild.include
scripts/Makefile.build
scripts/Makefile.host
scripts/Makefile.lib
scripts/Makefile.modpost
scripts/rt-tester/check-all.sh [new file with mode: 0644]
scripts/rt-tester/rt-tester.py [new file with mode: 0644]
scripts/rt-tester/t2-l1-2rt-sameprio.tst [new file with mode: 0644]
scripts/rt-tester/t2-l1-pi.tst [new file with mode: 0644]
scripts/rt-tester/t2-l1-signal.tst [new file with mode: 0644]
scripts/rt-tester/t2-l2-2rt-deadlock.tst [new file with mode: 0644]
scripts/rt-tester/t3-l1-pi-1rt.tst [new file with mode: 0644]
scripts/rt-tester/t3-l1-pi-2rt.tst [new file with mode: 0644]
scripts/rt-tester/t3-l1-pi-3rt.tst [new file with mode: 0644]
scripts/rt-tester/t3-l1-pi-signal.tst [new file with mode: 0644]
scripts/rt-tester/t3-l1-pi-steal.tst [new file with mode: 0644]
scripts/rt-tester/t3-l2-pi.tst [new file with mode: 0644]
scripts/rt-tester/t4-l2-pi-deboost.tst [new file with mode: 0644]
scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst [new file with mode: 0644]
scripts/rt-tester/t5-l4-pi-boost-deboost.tst [new file with mode: 0644]
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/request_key.c
security/selinux/hooks.c
sound/Makefile
sound/aoa/Kconfig
sound/aoa/core/snd-aoa-gpio-feature.c
sound/aoa/fabrics/snd-aoa-fabric-layout.c
sound/aoa/soundbus/Kconfig
sound/arm/aaci.c
sound/core/Kconfig
sound/core/info.c
sound/core/seq/seq_ports.c
sound/core/sound.c
sound/drivers/mpu401/mpu401.c
sound/i2c/other/ak4xxx-adda.c
sound/isa/es18xx.c
sound/isa/gus/interwave.c
sound/isa/sb/sb16.c
sound/oss/Kconfig
sound/oss/cs4232.c
sound/oss/forte.c
sound/oss/soundcard.c
sound/oss/via82cxxx_audio.c
sound/pci/Kconfig
sound/pci/Makefile
sound/pci/ac97/ac97_patch.c
sound/pci/bt87x.c
sound/pci/echoaudio/Makefile [new file with mode: 0644]
sound/pci/echoaudio/darla20.c [new file with mode: 0644]
sound/pci/echoaudio/darla20_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/darla24.c [new file with mode: 0644]
sound/pci/echoaudio/darla24_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/echo3g.c [new file with mode: 0644]
sound/pci/echoaudio/echo3g_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/echoaudio.c [new file with mode: 0644]
sound/pci/echoaudio/echoaudio.h [new file with mode: 0644]
sound/pci/echoaudio/echoaudio_3g.c [new file with mode: 0644]
sound/pci/echoaudio/echoaudio_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/echoaudio_dsp.h [new file with mode: 0644]
sound/pci/echoaudio/echoaudio_gml.c [new file with mode: 0644]
sound/pci/echoaudio/gina20.c [new file with mode: 0644]
sound/pci/echoaudio/gina20_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/gina24.c [new file with mode: 0644]
sound/pci/echoaudio/gina24_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/indigo.c [new file with mode: 0644]
sound/pci/echoaudio/indigo_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/indigodj.c [new file with mode: 0644]
sound/pci/echoaudio/indigodj_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/indigoio.c [new file with mode: 0644]
sound/pci/echoaudio/indigoio_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/layla20.c [new file with mode: 0644]
sound/pci/echoaudio/layla20_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/layla24.c [new file with mode: 0644]
sound/pci/echoaudio/layla24_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/mia.c [new file with mode: 0644]
sound/pci/echoaudio/mia_dsp.c [new file with mode: 0644]
sound/pci/echoaudio/midi.c [new file with mode: 0644]
sound/pci/echoaudio/mona.c [new file with mode: 0644]
sound/pci/echoaudio/mona_dsp.c [new file with mode: 0644]
sound/pci/hda/hda_codec.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/ice1712/revo.c
sound/pci/sonicvibes.c
sound/ppc/pmac.c
sound/ppc/toonie.c [deleted file]
sound/sound_core.c
sound/sparc/cs4231.c
sound/sparc/dbri.c
sound/usb/usbaudio.c

diff --git a/CREDITS b/CREDITS
index 85c7c70b7044bb9e098e6d87949709033ebdc3d5..66b9e7a9abff509fef1d8e7c9425fe0dfbb06ece 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -3401,10 +3401,10 @@ S: Czech Republic
 
 N: Thibaut Varene
 E: T-Bone@parisc-linux.org
-W: http://www.parisc-linux.org/
+W: http://www.parisc-linux.org/~varenet/
 P: 1024D/B7D2F063 E67C 0D43 A75E 12A5 BB1C  FA2F 1E32 C3DA B7D2 F063
 D: PA-RISC port minion, PDC and GSCPS2 drivers, debuglocks and other bits
-D: Some bits in an ARM port, S1D13XXX FB driver, random patches here and there
+D: Some ARM at91rm9200 bits, S1D13XXX FB driver, random patches here and there
 D: AD1889 sound driver
 S: Paris, France
 
index b02f476c297302bced86ee62fe89afe2066d3c70..488272074c36f348753817c4c07484fe8035da91 100644 (file)
@@ -181,8 +181,8 @@ Intel IA32 microcode
 --------------------
 
 A driver has been added to allow updating of Intel IA32 microcode,
-accessible as both a devfs regular file and as a normal (misc)
-character device.  If you are not using devfs you may need to:
+accessible as a normal (misc) character device.  If you are not using
+udev you may need to:
 
 mkdir /dev/cpu
 mknod /dev/cpu/microcode c 10 184
@@ -201,7 +201,9 @@ with programs using shared memory.
 udev
 ----
 udev is a userspace application for populating /dev dynamically with
-only entries for devices actually present. udev replaces devfs.
+only entries for devices actually present.  udev replaces the basic
+functionality of devfs, while allowing persistant device naming for
+devices.
 
 FUSE
 ----
@@ -231,18 +233,13 @@ The PPP driver has been restructured to support multilink and to
 enable it to operate over diverse media layers.  If you use PPP,
 upgrade pppd to at least 2.4.0.
 
-If you are not using devfs, you must have the device file /dev/ppp
+If you are not using udev, you must have the device file /dev/ppp
 which can be made by:
 
 mknod /dev/ppp c 108 0
 
 as root.
 
-If you use devfsd and build ppp support as modules, you will need
-the following in your /etc/devfsd.conf file:
-
-LOOKUP PPP     MODLOAD
-
 Isdn4k-utils
 ------------
 
index 5a2882d275ba5b3beabb305c62a22f38aa5cff44..66e1cf733571ccc4122dcc745bf9c713ee6559b6 100644 (file)
@@ -10,7 +10,8 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
            kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
            procfs-guide.xml writing_usb_driver.xml \
            kernel-api.xml journal-api.xml lsm.xml usb.xml \
-           gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml
+           gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
+           genericirq.xml
 
 ###
 # The build process is as follows (targets):
diff --git a/Documentation/DocBook/genericirq.tmpl b/Documentation/DocBook/genericirq.tmpl
new file mode 100644 (file)
index 0000000..0f4a4b6
--- /dev/null
@@ -0,0 +1,474 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="Generic-IRQ-Guide">
+ <bookinfo>
+  <title>Linux generic IRQ handling</title>
+
+  <authorgroup>
+   <author>
+    <firstname>Thomas</firstname>
+    <surname>Gleixner</surname>
+    <affiliation>
+     <address>
+      <email>tglx@linutronix.de</email>
+     </address>
+    </affiliation>
+   </author>
+   <author>
+    <firstname>Ingo</firstname>
+    <surname>Molnar</surname>
+    <affiliation>
+     <address>
+      <email>mingo@elte.hu</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2005-2006</year>
+   <holder>Thomas Gleixner</holder>
+  </copyright>
+  <copyright>
+   <year>2005-2006</year>
+   <holder>Ingo Molnar</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 interrupt handling layer is designed to provide a
+       complete abstraction of interrupt handling for device drivers.
+       It is able to handle all the different types of interrupt controller
+       hardware. Device drivers use generic API functions to request, enable,
+       disable and free interrupts. The drivers do not have to know anything
+       about interrupt hardware details, so they can be used on different
+       platforms without code changes.
+    </para>
+    <para>
+       This documentation is provided to developers who want to implement
+       an interrupt subsystem based for their architecture, with the help
+       of the generic IRQ handling layer.
+    </para>
+  </chapter>
+
+  <chapter id="rationale">
+    <title>Rationale</title>
+       <para>
+       The original implementation of interrupt handling in Linux is using
+       the __do_IRQ() super-handler, which is able to deal with every
+       type of interrupt logic.
+       </para>
+       <para>
+       Originally, Russell King identified different types of handlers to
+       build a quite universal set for the ARM interrupt handler
+       implementation in Linux 2.5/2.6. He distinguished between:
+       <itemizedlist>
+         <listitem><para>Level type</para></listitem>
+         <listitem><para>Edge type</para></listitem>
+         <listitem><para>Simple type</para></listitem>
+       </itemizedlist>
+       In the SMP world of the __do_IRQ() super-handler another type
+       was identified:
+       <itemizedlist>
+         <listitem><para>Per CPU type</para></listitem>
+       </itemizedlist>
+       </para>
+       <para>
+       This split implementation of highlevel IRQ handlers allows us to
+       optimize the flow of the interrupt handling for each specific
+       interrupt type. This reduces complexity in that particular codepath
+       and allows the optimized handling of a given type.
+       </para>
+       <para>
+       The original general IRQ implementation used hw_interrupt_type
+       structures and their ->ack(), ->end() [etc.] callbacks to
+       differentiate the flow control in the super-handler. This leads to
+       a mix of flow logic and lowlevel hardware logic, and it also leads
+       to unnecessary code duplication: for example in i386, there is a
+       ioapic_level_irq and a ioapic_edge_irq irq-type which share many
+       of the lowlevel details but have different flow handling.
+       </para>
+       <para>
+       A more natural abstraction is the clean separation of the
+       'irq flow' and the 'chip details'.
+       </para>
+       <para>
+       Analysing a couple of architecture's IRQ subsystem implementations
+       reveals that most of them can use a generic set of 'irq flow'
+       methods and only need to add the chip level specific code.
+       The separation is also valuable for (sub)architectures
+       which need specific quirks in the irq flow itself but not in the
+       chip-details - and thus provides a more transparent IRQ subsystem
+       design.
+       </para>
+       <para>
+       Each interrupt descriptor is assigned its own highlevel flow
+       handler, which is normally one of the generic
+       implementations. (This highlevel flow handler implementation also
+       makes it simple to provide demultiplexing handlers which can be
+       found in embedded platforms on various architectures.)
+       </para>
+       <para>
+       The separation makes the generic interrupt handling layer more
+       flexible and extensible. For example, an (sub)architecture can
+       use a generic irq-flow implementation for 'level type' interrupts
+       and add a (sub)architecture specific 'edge type' implementation.
+       </para>
+       <para>
+       To make the transition to the new model easier and prevent the
+       breakage of existing implementations, the __do_IRQ() super-handler
+       is still available. This leads to a kind of duality for the time
+       being. Over time the new model should be used in more and more
+       architectures, as it enables smaller and cleaner IRQ subsystems.
+       </para>
+  </chapter>
+  <chapter id="bugs">
+    <title>Known Bugs And Assumptions</title>
+    <para>
+       None (knock on wood).
+    </para>
+  </chapter>
+
+  <chapter id="Abstraction">
+    <title>Abstraction layers</title>
+    <para>
+       There are three main levels of abstraction in the interrupt code:
+       <orderedlist>
+         <listitem><para>Highlevel driver API</para></listitem>
+         <listitem><para>Highlevel IRQ flow handlers</para></listitem>
+         <listitem><para>Chiplevel hardware encapsulation</para></listitem>
+       </orderedlist>
+    </para>
+    <sect1>
+       <title>Interrupt control flow</title>
+       <para>
+       Each interrupt is described by an interrupt descriptor structure
+       irq_desc. The interrupt is referenced by an 'unsigned int' numeric
+       value which selects the corresponding interrupt decription structure
+       in the descriptor structures array.
+       The descriptor structure contains status information and pointers
+       to the interrupt flow method and the interrupt chip structure
+       which are assigned to this interrupt.
+       </para>
+       <para>
+       Whenever an interrupt triggers, the lowlevel arch code calls into
+       the generic interrupt code by calling desc->handle_irq().
+       This highlevel IRQ handling function only uses desc->chip primitives
+       referenced by the assigned chip descriptor structure.
+       </para>
+    </sect1>
+    <sect1>
+       <title>Highlevel Driver API</title>
+       <para>
+         The highlevel Driver API consists of following functions:
+         <itemizedlist>
+         <listitem><para>request_irq()</para></listitem>
+         <listitem><para>free_irq()</para></listitem>
+         <listitem><para>disable_irq()</para></listitem>
+         <listitem><para>enable_irq()</para></listitem>
+         <listitem><para>disable_irq_nosync() (SMP only)</para></listitem>
+         <listitem><para>synchronize_irq() (SMP only)</para></listitem>
+         <listitem><para>set_irq_type()</para></listitem>
+         <listitem><para>set_irq_wake()</para></listitem>
+         <listitem><para>set_irq_data()</para></listitem>
+         <listitem><para>set_irq_chip()</para></listitem>
+         <listitem><para>set_irq_chip_data()</para></listitem>
+          </itemizedlist>
+         See the autogenerated function documentation for details.
+       </para>
+    </sect1>
+    <sect1>
+       <title>Highlevel IRQ flow handlers</title>
+       <para>
+         The generic layer provides a set of pre-defined irq-flow methods:
+         <itemizedlist>
+         <listitem><para>handle_level_irq</para></listitem>
+         <listitem><para>handle_edge_irq</para></listitem>
+         <listitem><para>handle_simple_irq</para></listitem>
+         <listitem><para>handle_percpu_irq</para></listitem>
+         </itemizedlist>
+         The interrupt flow handlers (either predefined or architecture
+         specific) are assigned to specific interrupts by the architecture
+         either during bootup or during device initialization.
+       </para>
+       <sect2>
+       <title>Default flow implementations</title>
+           <sect3>
+               <title>Helper functions</title>
+               <para>
+               The helper functions call the chip primitives and
+               are used by the default flow implementations.
+               The following helper functions are implemented (simplified excerpt):
+               <programlisting>
+default_enable(irq)
+{
+       desc->chip->unmask(irq);
+}
+
+default_disable(irq)
+{
+       if (!delay_disable(irq))
+               desc->chip->mask(irq);
+}
+
+default_ack(irq)
+{
+       chip->ack(irq);
+}
+
+default_mask_ack(irq)
+{
+       if (chip->mask_ack) {
+               chip->mask_ack(irq);
+       } else {
+               chip->mask(irq);
+               chip->ack(irq);
+       }
+}
+
+noop(irq)
+{
+}
+
+               </programlisting>
+               </para>
+           </sect3>
+       </sect2>
+       <sect2>
+       <title>Default flow handler implementations</title>
+           <sect3>
+               <title>Default Level IRQ flow handler</title>
+               <para>
+               handle_level_irq provides a generic implementation
+               for level-triggered interrupts.
+               </para>
+               <para>
+               The following control flow is implemented (simplified excerpt):
+               <programlisting>
+desc->chip->start();
+handle_IRQ_event(desc->action);
+desc->chip->end();
+               </programlisting>
+               </para>
+           </sect3>
+           <sect3>
+               <title>Default Edge IRQ flow handler</title>
+               <para>
+               handle_edge_irq provides a generic implementation
+               for edge-triggered interrupts.
+               </para>
+               <para>
+               The following control flow is implemented (simplified excerpt):
+               <programlisting>
+if (desc->status &amp; running) {
+       desc->chip->hold();
+       desc->status |= pending | masked;
+       return;
+}
+desc->chip->start();
+desc->status |= running;
+do {
+       if (desc->status &amp; masked)
+               desc->chip->enable();
+       desc-status &amp;= ~pending;
+       handle_IRQ_event(desc->action);
+} while (status &amp; pending);
+desc-status &amp;= ~running;
+desc->chip->end();
+               </programlisting>
+               </para>
+           </sect3>
+           <sect3>
+               <title>Default simple IRQ flow handler</title>
+               <para>
+               handle_simple_irq provides a generic implementation
+               for simple interrupts.
+               </para>
+               <para>
+               Note: The simple flow handler does not call any
+               handler/chip primitives.
+               </para>
+               <para>
+               The following control flow is implemented (simplified excerpt):
+               <programlisting>
+handle_IRQ_event(desc->action);
+               </programlisting>
+               </para>
+           </sect3>
+           <sect3>
+               <title>Default per CPU flow handler</title>
+               <para>
+               handle_percpu_irq provides a generic implementation
+               for per CPU interrupts.
+               </para>
+               <para>
+               Per CPU interrupts are only available on SMP and
+               the handler provides a simplified version without
+               locking.
+               </para>
+               <para>
+               The following control flow is implemented (simplified excerpt):
+               <programlisting>
+desc->chip->start();
+handle_IRQ_event(desc->action);
+desc->chip->end();
+               </programlisting>
+               </para>
+           </sect3>
+       </sect2>
+       <sect2>
+       <title>Quirks and optimizations</title>
+       <para>
+       The generic functions are intended for 'clean' architectures and chips,
+       which have no platform-specific IRQ handling quirks. If an architecture
+       needs to implement quirks on the 'flow' level then it can do so by
+       overriding the highlevel irq-flow handler.
+       </para>
+       </sect2>
+       <sect2>
+       <title>Delayed interrupt disable</title>
+       <para>
+       This per interrupt selectable feature, which was introduced by Russell
+       King in the ARM interrupt implementation, does not mask an interrupt
+       at the hardware level when disable_irq() is called. The interrupt is
+       kept enabled and is masked in the flow handler when an interrupt event
+       happens. This prevents losing edge interrupts on hardware which does
+       not store an edge interrupt event while the interrupt is disabled at
+       the hardware level. When an interrupt arrives while the IRQ_DISABLED
+       flag is set, then the interrupt is masked at the hardware level and
+       the IRQ_PENDING bit is set. When the interrupt is re-enabled by
+       enable_irq() the pending bit is checked and if it is set, the
+       interrupt is resent either via hardware or by a software resend
+       mechanism. (It's necessary to enable CONFIG_HARDIRQS_SW_RESEND when
+       you want to use the delayed interrupt disable feature and your
+       hardware is not capable of retriggering an interrupt.)
+       The delayed interrupt disable can be runtime enabled, per interrupt,
+       by setting the IRQ_DELAYED_DISABLE flag in the irq_desc status field.
+       </para>
+       </sect2>
+    </sect1>
+    <sect1>
+       <title>Chiplevel hardware encapsulation</title>
+       <para>
+       The chip level hardware descriptor structure irq_chip
+       contains all the direct chip relevant functions, which
+       can be utilized by the irq flow implementations.
+         <itemizedlist>
+         <listitem><para>ack()</para></listitem>
+         <listitem><para>mask_ack() - Optional, recommended for performance</para></listitem>
+         <listitem><para>mask()</para></listitem>
+         <listitem><para>unmask()</para></listitem>
+         <listitem><para>retrigger() - Optional</para></listitem>
+         <listitem><para>set_type() - Optional</para></listitem>
+         <listitem><para>set_wake() - Optional</para></listitem>
+         </itemizedlist>
+       These primitives are strictly intended to mean what they say: ack means
+       ACK, masking means masking of an IRQ line, etc. It is up to the flow
+       handler(s) to use these basic units of lowlevel functionality.
+       </para>
+    </sect1>
+  </chapter>
+
+  <chapter id="doirq">
+     <title>__do_IRQ entry point</title>
+     <para>
+       The original implementation __do_IRQ() is an alternative entry
+       point for all types of interrupts.
+     </para>
+     <para>
+       This handler turned out to be not suitable for all
+       interrupt hardware and was therefore reimplemented with split
+       functionality for egde/level/simple/percpu interrupts. This is not
+       only a functional optimization. It also shortens code paths for
+       interrupts.
+      </para>
+      <para>
+       To make use of the split implementation, replace the call to
+       __do_IRQ by a call to desc->chip->handle_irq() and associate
+        the appropriate handler function to desc->chip->handle_irq().
+       In most cases the generic handler implementations should
+       be sufficient.
+     </para>
+  </chapter>
+
+  <chapter id="locking">
+     <title>Locking on SMP</title>
+     <para>
+       The locking of chip registers is up to the architecture that
+       defines the chip primitives. There is a chip->lock field that can be used
+       for serialization, but the generic layer does not touch it. The per-irq
+       structure is protected via desc->lock, by the generic layer.
+     </para>
+  </chapter>
+  <chapter id="structs">
+     <title>Structures</title>
+     <para>
+     This chapter contains the autogenerated documentation of the structures which are
+     used in the generic IRQ layer.
+     </para>
+!Iinclude/linux/irq.h
+  </chapter>
+
+  <chapter id="pubfunctions">
+     <title>Public Functions Provided</title>
+     <para>
+     This chapter contains the autogenerated documentation of the kernel API functions
+      which are exported.
+     </para>
+!Ekernel/irq/manage.c
+!Ekernel/irq/chip.c
+  </chapter>
+
+  <chapter id="intfunctions">
+     <title>Internal Functions Provided</title>
+     <para>
+     This chapter contains the autogenerated documentation of the internal functions.
+     </para>
+!Ikernel/irq/handle.c
+!Ikernel/irq/chip.c
+  </chapter>
+
+  <chapter id="credits">
+     <title>Credits</title>
+       <para>
+               The following people have contributed to this document:
+               <orderedlist>
+                       <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem>
+                       <listitem><para>Ingo Molnar<email>mingo@elte.hu</email></para></listitem>
+               </orderedlist>
+       </para>
+  </chapter>
+</book>
index 3630a0d7695f91f98dfa0844370ca7af3048620a..1ae4dc0fd8564db5801951997946603f0ce4a79d 100644 (file)
@@ -348,11 +348,6 @@ X!Earch/i386/kernel/mca.c
      </sect1>
   </chapter>
 
-  <chapter id="devfs">
-     <title>The Device File System</title>
-!Efs/devfs/base.c
-  </chapter>
-
   <chapter id="sysfs">
      <title>The Filesystem for Exporting Kernel Objects</title>
 !Efs/sysfs/file.c
diff --git a/Documentation/IRQ.txt b/Documentation/IRQ.txt
new file mode 100644 (file)
index 0000000..1011e71
--- /dev/null
@@ -0,0 +1,22 @@
+What is an IRQ?
+
+An IRQ is an interrupt request from a device.
+Currently they can come in over a pin, or over a packet.
+Several devices may be connected to the same pin thus
+sharing an IRQ.
+
+An IRQ number is a kernel identifier used to talk about a hardware
+interrupt source.  Typically this is an index into the global irq_desc
+array, but except for what linux/interrupt.h implements the details
+are architecture specific.
+
+An IRQ number is an enumeration of the possible interrupt sources on a
+machine.  Typically what is enumerated is the number of input pins on
+all of the interrupt controller in the system.  In the case of ISA
+what is enumerated are the 16 input pins on the two i8259 interrupt
+controllers.
+
+Architectures can assign additional meaning to the IRQ numbers, and
+are encouraged to in the case  where there is any manual configuration
+of the hardware involved.  The ISA IRQs are a classic example of
+assigning this kind of additional meaning.
index e4c38152f7f799b94a70493f90dbf36b830e9cde..a4948591607d0e1d7b653ce1f66c08e4831cbad1 100644 (file)
@@ -7,7 +7,7 @@ The CONFIG_RCU_TORTURE_TEST config option is available for all RCU
 implementations.  It creates an rcutorture kernel module that can
 be loaded to run a torture test.  The test periodically outputs
 status messages via printk(), which can be examined via the dmesg
-command (perhaps grepping for "rcutorture").  The test is started
+command (perhaps grepping for "torture").  The test is started
 when the module is loaded, and stops when the module is unloaded.
 
 However, actually setting this config option to "y" results in the system
@@ -35,6 +35,19 @@ stat_interval        The number of seconds between output of torture
                be printed -only- when the module is unloaded, and this
                is the default.
 
+shuffle_interval
+               The number of seconds to keep the test threads affinitied
+               to a particular subset of the CPUs.  Used in conjunction
+               with test_no_idle_hz.
+
+test_no_idle_hz        Whether or not to test the ability of RCU to operate in
+               a kernel that disables the scheduling-clock interrupt to
+               idle CPUs.  Boolean parameter, "1" to test, "0" otherwise.
+
+torture_type   The type of RCU to test: "rcu" for the rcu_read_lock()
+               API, "rcu_bh" for the rcu_read_lock_bh() API, and "srcu"
+               for the "srcu_read_lock()" API.
+
 verbose                Enable debug printk()s.  Default is disabled.
 
 
@@ -42,14 +55,14 @@ OUTPUT
 
 The statistics output is as follows:
 
-       rcutorture: --- Start of test: nreaders=16 stat_interval=0 verbose=0
-       rcutorture: rtc: 0000000000000000 ver: 1916 tfle: 0 rta: 1916 rtaf: 0 rtf: 1915
-       rcutorture: Reader Pipe:  1466408 9747 0 0 0 0 0 0 0 0 0
-       rcutorture: Reader Batch:  1464477 11678 0 0 0 0 0 0 0 0
-       rcutorture: Free-Block Circulation:  1915 1915 1915 1915 1915 1915 1915 1915 1915 1915 0
-       rcutorture: --- End of test
+       rcu-torture: --- Start of test: nreaders=16 stat_interval=0 verbose=0
+       rcu-torture: rtc: 0000000000000000 ver: 1916 tfle: 0 rta: 1916 rtaf: 0 rtf: 1915
+       rcu-torture: Reader Pipe:  1466408 9747 0 0 0 0 0 0 0 0 0
+       rcu-torture: Reader Batch:  1464477 11678 0 0 0 0 0 0 0 0
+       rcu-torture: Free-Block Circulation:  1915 1915 1915 1915 1915 1915 1915 1915 1915 1915 0
+       rcu-torture: --- End of test
 
-The command "dmesg | grep rcutorture:" will extract this information on
+The command "dmesg | grep torture:" will extract this information on
 most systems.  On more esoteric configurations, it may be necessary to
 use other commands to access the output of the printk()s used by
 the RCU torture test.  The printk()s use KERN_ALERT, so they should
@@ -115,8 +128,9 @@ The following script may be used to torture RCU:
        modprobe rcutorture
        sleep 100
        rmmod rcutorture
-       dmesg | grep rcutorture:
+       dmesg | grep torture:
 
 The output can be manually inspected for the error flag of "!!!".
 One could of course create a more elaborate script that automatically
-checked for such errors.
+checked for such errors.  The "rmmod" command forces a "SUCCESS" or
+"FAILURE" indication to be printk()ed.
index 98ea617a0dd6ea7b604610b786254db0f5fc7c44..0e8f618ab5344c3cbb6af186efcb4a0920a212db 100644 (file)
@@ -78,9 +78,9 @@ also known as "System Drives", and Drive Groups are also called "Packs".  Both
 terms are in use in the Mylex documentation; I have chosen to standardize on
 the more generic "Logical Drive" and "Drive Group".
 
-DAC960 RAID disk devices are named in the style of the Device File System
-(DEVFS).  The device corresponding to Logical Drive D on Controller C is
-referred to as /dev/rd/cCdD, and the partitions are called /dev/rd/cCdDp1
+DAC960 RAID disk devices are named in the style of the obsolete Device File
+System (DEVFS).  The device corresponding to Logical Drive D on Controller C
+is referred to as /dev/rd/cCdD, and the partitions are called /dev/rd/cCdDp1
 through /dev/rd/cCdDp7.  For example, partition 3 of Logical Drive 5 on
 Controller 2 is referred to as /dev/rd/c2d5p3.  Note that unlike with SCSI
 disks the device names will not change in the event of a disk drive failure.
index 027285d0c26c1e4e366237e2893b12c231b37a78..1cbbb8e28999fc0cc8d980700b2bc3e772790d5e 100644 (file)
@@ -6,17 +6,6 @@ be removed from this file.
 
 ---------------------------
 
-What:  devfs
-When:  July 2005
-Files: fs/devfs/*, include/linux/devfs_fs*.h and assorted devfs
-       function calls throughout the kernel tree
-Why:   It has been unmaintained for a number of years, has unfixable
-       races, contains a naming policy within the kernel that is
-       against the LSB, and can be replaced by using udev.
-Who:   Greg Kroah-Hartman <greg@kroah.com>
-
----------------------------
-
 What:  RAW driver (CONFIG_RAW_DRIVER)
 When:  December 2005
 Why:   declared obsolete since kernel 2.6.3
@@ -132,16 +121,6 @@ Who:       NeilBrown <neilb@suse.de>
 
 ---------------------------
 
-What:  au1x00_uart driver
-When:  January 2006
-Why:   The 8250 serial driver now has the ability to deal with the differences
-       between the standard 8250 family of UARTs and their slightly strange
-       brother on Alchemy SOCs.  The loss of features is not considered an
-       issue.
-Who:   Ralf Baechle <ralf@linux-mips.org>
-
----------------------------
-
 What:   eepro100 network driver
 When:   January 2007
 Why:    replaced by the e100 driver
@@ -177,6 +156,16 @@ Who:       Jean Delvare <khali@linux-fr.org>
 
 ---------------------------
 
+What:  Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
+       (temporary transition config option provided until then)
+       The transition config option will also be removed at the same time.
+When:  before 2.6.19
+Why:   Unused symbols are both increasing the size of the kernel binary
+       and are often a sign of "wrong API"
+Who:   Arjan van de Ven <arjan@linux.intel.com>
+
+---------------------------
+
 What:  remove EXPORT_SYMBOL(tasklist_lock)
 When:  August 2006
 Files: kernel/fork.c
@@ -224,3 +213,47 @@ Why:       The interface no longer has any callers left in the kernel. It
 Who:   Nick Piggin <npiggin@suse.de>
 
 ---------------------------
+
+What:  Support for the MIPS EV96100 evaluation board
+When:  September 2006
+Why:   Does no longer build since at least November 15, 2003, apparently
+       no userbase left.
+Who:   Ralf Baechle <ralf@linux-mips.org>
+
+---------------------------
+
+What:  Support for the Momentum / PMC-Sierra Jaguar ATX evaluation board
+When:  September 2006
+Why:   Does no longer build since quite some time, and was never popular,
+       due to the platform being replaced by successor models.  Apparently
+       no user base left.  It also is one of the last users of
+       WANT_PAGE_VIRTUAL.
+Who:   Ralf Baechle <ralf@linux-mips.org>
+
+---------------------------
+
+What:  Support for the Momentum Ocelot, Ocelot 3, Ocelot C and Ocelot G
+When:  September 2006
+Why:   Some do no longer build and apparently there is no user base left
+       for these platforms.
+Who:   Ralf Baechle <ralf@linux-mips.org>
+
+---------------------------
+
+What:  Support for MIPS Technologies' Altas and SEAD evaluation board
+When:  September 2006
+Why:   Some do no longer build and apparently there is no user base left
+       for these platforms.  Hardware out of production since several years.
+Who:   Ralf Baechle <ralf@linux-mips.org>
+
+---------------------------
+
+What:  Support for the IT8172-based platforms, ITE 8172G and Globespan IVR
+When:  September 2006
+Why:   Code does no longer build since at least 2.6.0,  apparently there is
+       no user base left for these platforms.  Hardware out of production
+       since several years and hardly a trace of the manufacturer left on
+       the net.
+Who:   Ralf Baechle <ralf@linux-mips.org>
+
+---------------------------
diff --git a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog
deleted file mode 100644 (file)
index e5aba52..0000000
+++ /dev/null
@@ -1,1977 +0,0 @@
-/* -*- auto-fill -*-                                                         */
-===============================================================================
-Changes for patch v1
-
-- creation of devfs
-
-- modified miscellaneous character devices to support devfs
-===============================================================================
-Changes for patch v2
-
-- bug fix with manual inode creation
-===============================================================================
-Changes for patch v3
-
-- bugfixes
-
-- documentation improvements
-
-- created a couple of scripts (one to save&restore a devfs and the
-  other to set up compatibility symlinks)
-
-- devfs support for SCSI discs. New name format is: sd_hHcCiIlL
-===============================================================================
-Changes for patch v4
-
-- bugfix for the directory reading code
-
-- bugfix for compilation with kerneld
-
-- devfs support for generic hard discs
-
-- rationalisation of the various watchdog drivers
-===============================================================================
-Changes for patch v5
-
-- support for mounting directly from entries in the devfs (it doesn't
-  need to be mounted to do this), including the root filesystem.
-  Mounting of swap partitions also works. Hence, now if you set
-  CONFIG_DEVFS_ONLY to 'Y' then you won't be able to access your discs
-  via ordinary device nodes. Naturally, the default is 'N' so that you
-  can still use your old device nodes.  If you want to mount from devfs
-  entries, make sure you use: append = "root=/dev/sd_..." in your
-  lilo.conf. It seems LILO looks for the device number (major&minor)
-  and writes that into the kernel image :-( 
-
-- support for character memory devices (/dev/null, /dev/zero, /dev/full
-  and so on). Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-===============================================================================
-Changes for patch v6
-
-- support for subdirectories
-
-- support for symbolic links (created by devfs_mk_symlink(), no
-  support yet for creation via symlink(2))
-
-- SCSI disc naming now cast in stone, with the format:
-  /dev/sd/c0b1t2u3     controller=0, bus=1, ID=2, LUN=3, whole disc
-  /dev/sd/c0b1t2u3p4   controller=0, bus=1, ID=2, LUN=3, 4th partition
-
-- loop devices now appear in devfs
-
-- tty devices, console, serial ports, etc. now appear in devfs
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- bugs with mounting devfs-only devices now fixed
-===============================================================================
-Changes for patch v7
-
-- SCSI CD-ROMS, tapes and generic devices now appear in devfs
-===============================================================================
-Changes for patch v8
-
-- bugfix with no-rewind SCSI tapes
-
-- RAMDISCs now appear in devfs
-
-- better cleaning up of devfs entries created by various modules
-
-- interface change to <devfs_register>
-===============================================================================
-Changes for patch v9
-
-- the v8 patch was corrupted somehow, which would affect the patch for
-  linux/fs/filesystems.c
-  I've also fixed the v8 patch file on the WWW
-
-- MetaDevices (/dev/md*) should now appear in devfs
-===============================================================================
-Changes for patch v10
-
-- bugfix in meta device support for devfs
-
-- created this ChangeLog file
-
-- added devfs support to the floppy driver
-
-- added support for creating sockets in a devfs
-===============================================================================
-Changes for patch v11
-
-- added DEVFS_FL_HIDE_UNREG flag
-
-- incorporated better patch for ttyname() in libc 5.4.43 from H.J. Lu.
-
-- interface change to <devfs_mk_symlink>
-
-- support for creating symlinks with symlink(2)
-
-- parallel port printer (/dev/lp*) now appears in devfs
-===============================================================================
-Changes for patch v12
-
-- added inode check to <devfs_fill_file> function
-
-- improved devfs support when mounting from devfs
-
-- added call to <<release>> operation when removing swap areas on
-  devfs devices
-
-- increased NR_SUPER to 128 to support large numbers of devfs mounts
-  (for chroot(2) gaols)
-
-- fixed bug in SCSI disc support: was generating incorrect minors if
-  SCSI ID's did not start at 0 and increase by 1
-
-- support symlink traversal when mounting root
-===============================================================================
-Changes for patch v13
-
-- added devfs support to soundcard driver
-  Thanks to Eric Dumas <dumas@linux.eu.org> and
-  C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- added devfs support to the joystick driver
-
-- loop driver now has it's own subdirectory "/dev/loop/"
-
-- created <devfs_get_flags> and <devfs_set_flags> functions
-
-- fix problem with SCSI disc compatibility names (sd{a,b,c,d,e,f})
-  which assumes ID's start at 0 and increase by 1. Also only create
-  devfs entries for SCSI disc partitions which actually exist
-  Show new names in partition check
-  Thanks to Jakub Jelinek <jj@sunsite.ms.mff.cuni.cz>
-===============================================================================
-Changes for patch v14
-
-- bug fix in floppy driver: would not compile without
-  CONFIG_DEVFS_FS='Y'
-  Thanks to Jurgen Botz <jbotz@nova.botz.org>
-
-- bug fix in loop driver
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- do not create devfs entries for printers not configured
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- do not create devfs entries for serial ports not present
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- ensure <tty_register_devfs> is exported from tty_io.c
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- allow unregistering of devfs symlink entries
-
-- fixed bug in SCSI disc naming introduced in last patch version
-===============================================================================
-Changes for patch v15
-
-- ported to kernel 2.1.81
-===============================================================================
-Changes for patch v16
-
-- created <devfs_set_symlink_destination> function
-
-- moved DEVFS_SUPER_MAGIC into header file
-
-- added DEVFS_FL_HIDE flag
-
-- created <devfs_get_maj_min>
-
-- created <devfs_get_handle_from_inode>
-
-- fixed bugs in searching by major&minor
-
-- changed interface to <devfs_unregister>, <devfs_fill_file> and
-  <devfs_find_handle>
-
-- fixed inode times when symlink created with symlink(2)
-
-- change tty driver to do auto-creation of devfs entries
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- fixed bug in genhd.c: whole disc (non-SCSI) was not registered to
-  devfs
-
-- updated libc 5.4.43 patch for ttyname()
-===============================================================================
-Changes for patch v17
-
-- added CONFIG_DEVFS_TTY_COMPAT
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- bugfix in devfs support for drivers/char/lp.c
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- clean up serial driver so that PCMCIA devices unregister correctly
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- fixed bug in genhd.c: whole disc (non-SCSI) was not registered to
-  devfs [was missing in patch v16]
-
-- updated libc 5.4.43 patch for ttyname() [was missing in patch v16]
-
-- all SCSI devices now registered in /dev/sg
-
-- support removal of devfs entries via unlink(2)
-===============================================================================
-Changes for patch v18
-
-- added floppy/?u720 floppy entry
-
-- fixed kerneld support for entries in devfs subdirectories
-
-- incorporated latest patch for ttyname() in libc 5.4.43 from H.J. Lu.
-===============================================================================
-Changes for patch v19
-
-- bug fix when looking up unregistered entries: kerneld was not called
-
-- fixes for kernel 2.1.86 (now requires 2.1.86)
-===============================================================================
-Changes for patch v20
-
-- only create available floppy entries
-  Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
-
-- new IDE naming scheme following SCSI format (i.e. /dev/id/c0b0t0u0p1
-  instead of /dev/hda1)
-  Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
-
-- new XT disc naming scheme following SCSI format (i.e. /dev/xd/c0t0p1
-  instead of /dev/xda1)
-  Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
-
-- new non-standard CD-ROM names (i.e. /dev/sbp/c#t#)
-  Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
-
-- allow symlink traversal when mounting the root filesystem
-
-- Create entries for MD devices at MD init
-  Thanks to Christophe Leroy <christophe.leroy5@capway.com>
-===============================================================================
-Changes for patch v21
-
-- ported to kernel 2.1.91
-===============================================================================
-Changes for patch v22
-
-- SCSI host number patch ("scsihosts=" kernel option)
-  Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
-===============================================================================
-Changes for patch v23
-
-- Fixed persistence bug with device numbers for manually created
-  device files
-
-- Fixed problem with recreating symlinks with different content
-
-- Added CONFIG_DEVFS_MOUNT (mount devfs on /dev at boot time)
-===============================================================================
-Changes for patch v24
-
-- Switched from CONFIG_KERNELD to CONFIG_KMOD: module autoloading
-  should now work again
-
-- Hide entries which are manually unlinked
-
-- Always invalidate devfs dentry cache when registering entries
-
-- Support removal of devfs directories via rmdir(2)
-
-- Ensure directories created by <devfs_mk_dir> are visible
-
-- Default no access for "other" for floppy device
-===============================================================================
-Changes for patch v25
-
-- Updates to CREDITS file and minor IDE numbering change
-  Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
-
-- Invalidate devfs dentry cache when making directories
-
-- Invalidate devfs dentry cache when removing entries
-
-- More informative message if root FS mount fails when devfs
-  configured
-
-- Fixed persistence bug with fifos
-===============================================================================
-Changes for patch v26
-
-- ported to kernel 2.1.97
-
-- Changed serial directory from "/dev/serial" to "/dev/tts" and
-  "/dev/consoles" to "/dev/vc" to be more friendly to new procps
-===============================================================================
-Changes for patch v27
-
-- Added support for IDE4 and IDE5
-  Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
-
-- Documented "scsihosts=" boot parameter
-
-- Print process command when debugging kerneld/kmod
-
-- Added debugging for register/unregister/change operations
-
-- Added "devfs=" boot options
-
-- Hide unregistered entries by default
-===============================================================================
-Changes for patch v28
-
-- No longer lock/unlock superblock in <devfs_put_super> (cope with
-  recent VFS interface change)
-
-- Do not automatically change ownership/protection of /dev/tty
-
-- Drop negative dentries when they are released
-
-- Manage dcache more efficiently
-===============================================================================
-Changes for patch v29
-
-- Added DEVFS_FL_AUTO_DEVNUM flag
-===============================================================================
-Changes for patch v30
-
-- No longer set unnecessary methods
-
-- Ported to kernel 2.1.99-pre3
-===============================================================================
-Changes for patch v31
-
-- Added PID display to <call_kerneld> debugging message
-
-- Added "diread" and "diwrite" options
-
-- Ported to kernel 2.1.102
-
-- Fixed persistence problem with permissions
-===============================================================================
-Changes for patch v32
-
-- Fixed devfs support in drivers/block/md.c
-===============================================================================
-Changes for patch v33
-
-- Support legacy device nodes
-
-- Fixed bug where recreated inodes were hidden
-
-- New IDE naming scheme: everything is under /dev/ide
-===============================================================================
-Changes for patch v34
-
-- Improved debugging in <get_vfs_inode>
-
-- Prevent duplicate calls to <devfs_mk_dir> in SCSI layer
-
-- No longer free old dentries in <devfs_mk_dir>
-
-- Free all dentries for a given entry when deleting inodes
-===============================================================================
-Changes for patch v35
-
-- Ported to kernel 2.1.105 (sound driver changes)
-===============================================================================
-Changes for patch v36
-
-- Fixed sound driver port
-===============================================================================
-Changes for patch v37
-
-- Minor documentation tweaks
-===============================================================================
-Changes for patch v38
-
-- More documentation tweaks
-
-- Fix for sound driver port
-
-- Removed ttyname-patch (grab libc 5.4.44 instead)
-
-- Ported to kernel 2.1.107-pre2 (loop driver fix)
-===============================================================================
-Changes for patch v39
-
-- Ported to kernel 2.1.107 (hd.c hunk broke due to spelling "fixes"). Sigh
-
-- Removed many #ifdef's, replaced with trickery in include/devfs_fs.h
-===============================================================================
-Changes for patch v40
-
-- Fix for sound driver port
-
-- Limit auto-device numbering to majors 128 to 239
-===============================================================================
-Changes for patch v41
-
-- Fixed inode times persistence problem
-===============================================================================
-Changes for patch v42
-
-- Ported to kernel 2.1.108 (drivers/scsi/hosts.c hunk broke)
-===============================================================================
-Changes for patch v43
-
-- Fixed spelling in <devfs_readlink> debug
-
-- Fixed bug in <devfs_setup> parsing "dilookup"
-
-- More #ifdef's removed
-
-- Supported Sparc keyboard (/dev/kbd)
-
-- Supported DSP56001 digital signal processor (/dev/dsp56k)
-
-- Supported Apple Desktop Bus (/dev/adb)
-
-- Supported Coda network file system (/dev/cfs*)
-===============================================================================
-Changes for patch v44
-
-- Fixed devfs inode leak when manually recreating inodes
-
-- Fixed permission persistence problem when recreating inodes
-===============================================================================
-Changes for patch v45
-
-- Ported to kernel 2.1.110
-===============================================================================
-Changes for patch v46
-
-- Ported to kernel 2.1.112-pre1
-
-- Removed harmless "unused variable" compiler warning
-
-- Fixed modes for manually recreated device nodes
-===============================================================================
-Changes for patch v47
-
-- Added NULL devfs inode warning in <devfs_read_inode>
-
-- Force all inode nlink values to 1
-===============================================================================
-Changes for patch v48
-
-- Added "dimknod" option
-
-- Set inode nlink to 0 when freeing dentries
-
-- Added support for virtual console capture devices (/dev/vcs*)
-  Thanks to Dennis Hou <smilax@mindmeld.yi.org>
-
-- Fixed modes for manually recreated symlinks
-===============================================================================
-Changes for patch v49
-
-- Ported to kernel 2.1.113
-===============================================================================
-Changes for patch v50
-
-- Fixed bugs in recreated directories and symlinks
-===============================================================================
-Changes for patch v51
-
-- Improved robustness of rc.devfs script
-  Thanks to Roderich Schupp <rsch@experteam.de>
-
-- Fixed bugs in recreated device nodes
-
-- Fixed bug in currently unused <devfs_get_handle_from_inode>
-
-- Defined new <devfs_handle_t> type
-
-- Improved debugging when getting entries
-
-- Fixed bug where directories could be emptied
-
-- Ported to kernel 2.1.115
-===============================================================================
-Changes for patch v52
-
-- Replaced dummy .epoch inode with .devfsd character device
-
-- Modified rc.devfs to take account of above change
-
-- Removed spurious driver warning messages when CONFIG_DEVFS_FS=n
-
-- Implemented devfsd protocol revision 0
-===============================================================================
-Changes for patch v53
-
-- Ported to kernel 2.1.116 (kmod change broke hunk)
-
-- Updated Documentation/Configure.help
-
-- Test and tty pattern patch for rc.devfs script
-  Thanks to Roderich Schupp <rsch@experteam.de>
-
-- Added soothing message to warning in <devfs_d_iput>
-===============================================================================
-Changes for patch v54
-
-- Ported to kernel 2.1.117
-
-- Fixed default permissions in sound driver
-
-- Added support for frame buffer devices (/dev/fb*)
-===============================================================================
-Changes for patch v55
-
-- Ported to kernel 2.1.119
-
-- Use GCC extensions for structure initialisations
-
-- Implemented async open notification
-
-- Incremented devfsd protocol revision to 1
-===============================================================================
-Changes for patch v56
-
-- Ported to kernel 2.1.120-pre3
-
-- Moved async open notification to end of <devfs_open>
-===============================================================================
-Changes for patch v57
-
-- Ported to kernel 2.1.121
-
-- Prepended "/dev/" to module load request
-
-- Renamed <call_kerneld> to <call_kmod>
-
-- Created sample modules.conf file
-===============================================================================
-Changes for patch v58
-
-- Fixed typo "AYSNC" -> "ASYNC"
-===============================================================================
-Changes for patch v59
-
-- Added open flag for files
-===============================================================================
-Changes for patch v60
-
-- Ported to kernel 2.1.123-pre2
-===============================================================================
-Changes for patch v61
-
-- Set i_blocks=0 and i_blksize=1024 in <devfs_read_inode>
-===============================================================================
-Changes for patch v62
-
-- Ported to kernel 2.1.123
-===============================================================================
-Changes for patch v63
-
-- Ported to kernel 2.1.124-pre2
-===============================================================================
-Changes for patch v64
-
-- Fixed Unix98 pty support
-
-- Increased buffer size in <get_partition_list> to avoid crash and
-  burn
-===============================================================================
-Changes for patch v65
-
-- More Unix98 pty support fixes
-
-- Added test for empty <<name>> in <devfs_find_handle>
-
-- Renamed <generate_path> to <devfs_generate_path> and published
-
-- Created /dev/root symlink
-  Thanks to Roderich Schupp <rsch@ExperTeam.de>
-  with further modifications by me
-===============================================================================
-Changes for patch v66
-
-- Yet more Unix98 pty support fixes (now tested)
-
-- Created <devfs_get_fops>
-
-- Support media change checks when CONFIG_DEVFS_ONLY=y
-
-- Abolished Unix98-style PTY names for old PTY devices
-===============================================================================
-Changes for patch v67
-
-- Added inline declaration for dummy <devfs_generate_path>
-
-- Removed spurious "unable to register... in devfs" messages when
-  CONFIG_DEVFS_FS=n
-
-- Fixed misc. devices when CONFIG_DEVFS_FS=n
-
-- Limit auto-device numbering to majors 144 to 239
-===============================================================================
-Changes for patch v68
-
-- Hide unopened virtual consoles from directory listings
-
-- Added support for video capture devices
-
-- Ported to kernel 2.1.125
-===============================================================================
-Changes for patch v69
-
-- Fix for CONFIG_VT=n
-===============================================================================
-Changes for patch v70
-
-- Added support for non-OSS/Free sound cards
-===============================================================================
-Changes for patch v71
-
-- Ported to kernel 2.1.126-pre2
-===============================================================================
-Changes for patch v72
-
-- #ifdef's for CONFIG_DEVFS_DISABLE_OLD_NAMES removed
-===============================================================================
-Changes for patch v73
-
-- CONFIG_DEVFS_DISABLE_OLD_NAMES replaced with "nocompat" boot option
-
-- CONFIG_DEVFS_BOOT_OPTIONS removed: boot options always available
-===============================================================================
-Changes for patch v74
-
-- Removed CONFIG_DEVFS_MOUNT and "mount" boot option and replaced with
-  "nomount" boot option
-
-- Documentation updates
-
-- Updated sample modules.conf
-===============================================================================
-Changes for patch v75
-
-- Updated sample modules.conf
-
-- Remount devfs after initrd finishes
-
-- Ported to kernel 2.1.127
-
-- Added support for ISDN
-  Thanks to Christophe Leroy <christophe.leroy5@capway.com>
-===============================================================================
-Changes for patch v76
-
-- Updated an email address in ChangeLog
-
-- CONFIG_DEVFS_ONLY replaced with "only" boot option
-===============================================================================
-Changes for patch v77
-
-- Added DEVFS_FL_REMOVABLE flag
-
-- Check for disc change when listing directories with removable media
-  devices
-
-- Use DEVFS_FL_REMOVABLE in sd.c
-
-- Ported to kernel 2.1.128
-===============================================================================
-Changes for patch v78
-
-- Only call <scan_dir_for_removable> on first call to <devfs_readdir>
-
-- Ported to kernel 2.1.129-pre5
-
-- ISDN support improvements
-  Thanks to Christophe Leroy <christophe.leroy5@capway.com>
-===============================================================================
-Changes for patch v79
-
-- Ported to kernel 2.1.130
-
-- Renamed miscdevice "apm" to "apm_bios" to be consistent with
-  devices.txt
-===============================================================================
-Changes for patch v80
-
-- Ported to kernel 2.1.131
-
-- Updated <devfs_rmdir> for VFS change in 2.1.131
-===============================================================================
-Changes for patch v81
-
-- Fixed permissions on /dev/ptmx
-===============================================================================
-Changes for patch v82
-
-- Ported to kernel 2.1.132-pre4
-
-- Changed initial permissions on /dev/pts/*
-
-- Created <devfs_mk_compat>
-
-- Added "symlinks" boot option
-
-- Changed devfs_register_blkdev() back to register_blkdev() for IDE
-
-- Check for partitions on removable media in <devfs_lookup>
-===============================================================================
-Changes for patch v83
-
-- Fixed support for ramdisc when using string-based root FS name
-
-- Ported to kernel 2.2.0-pre1
-===============================================================================
-Changes for patch v84
-
-- Ported to kernel 2.2.0-pre7
-===============================================================================
-Changes for patch v85
-
-- Compile fixes for driver/sound/sound_common.c (non-module) and
-  drivers/isdn/isdn_common.c
-  Thanks to Christophe Leroy <christophe.leroy5@capway.com>
-
-- Added support for registering regular files
-
-- Created <devfs_set_file_size>
-
-- Added /dev/cpu/mtrr as an alternative interface to /proc/mtrr
-
-- Update devfs inodes from entries if not changed through FS
-===============================================================================
-Changes for patch v86
-
-- Ported to kernel 2.2.0-pre9
-===============================================================================
-Changes for patch v87
-
-- Fixed bug when mounting non-devfs devices in a devfs
-===============================================================================
-Changes for patch v88
-
-- Fixed <devfs_fill_file> to only initialise temporary inodes
-
-- Trap for NULL fops in <devfs_register>
-
-- Return -ENODEV in <devfs_fill_file> for non-driver inodes
-
-- Fixed bug when unswapping non-devfs devices in a devfs
-===============================================================================
-Changes for patch v89
-
-- Switched to C data types in include/linux/devfs_fs.h
-
-- Switched from PATH_MAX to DEVFS_PATHLEN
-
-- Updated Documentation/filesystems/devfs/modules.conf to take account
-  of reverse scanning (!) by modprobe
-
-- Ported to kernel 2.2.0
-===============================================================================
-Changes for patch v90
-
-- CONFIG_DEVFS_DISABLE_OLD_TTY_NAMES replaced with "nottycompat" boot
-  option
-
-- CONFIG_DEVFS_TTY_COMPAT removed: existing "symlinks" boot option now
-  controls this. This means you must have libc 5.4.44 or later, or a
-  recent version of libc 6 if you use the "symlinks" option
-===============================================================================
-Changes for patch v91
-
-- Switch from <devfs_mk_symlink> to <devfs_mk_compat> in
-  drivers/char/vc_screen.c to fix problems with Midnight Commander
-===============================================================================
-Changes for patch v92
-
-- Ported to kernel 2.2.2-pre5
-===============================================================================
-Changes for patch v93
-
-- Modified <sd_name> in drivers/scsi/sd.c to cope with devices that
-  don't exist (which happens with new RAID autostart code printk()s)
-===============================================================================
-Changes for patch v94
-
-- Fixed bug in joystick driver: only first joystick was registered
-===============================================================================
-Changes for patch v95
-
-- Fixed another bug in joystick driver
-
-- Fixed <devfsd_read> to not overrun event buffer
-===============================================================================
-Changes for patch v96
-
-- Ported to kernel 2.2.5-2
-
-- Created <devfs_auto_unregister>
-
-- Fixed bugs: compatibility entries were not unregistered for:
-    loop driver
-    floppy driver
-    RAMDISC driver
-    IDE tape driver
-    SCSI CD-ROM driver
-    SCSI HDD driver
-===============================================================================
-Changes for patch v97
-
-- Fixed bugs: compatibility entries were not unregistered for:
-    ALSA sound driver
-    partitions in generic disc driver
-
-- Don't return unregistred entries in <devfs_find_handle>
-
-- Panic in <devfs_unregister> if entry unregistered
-
-- Don't panic in <devfs_auto_unregister> for duplicates
-===============================================================================
-Changes for patch v98
-
-- Don't unregister already unregistered entries in <unregister>
-
-- Register entry in <sd_detect>
-
-- Unregister entry in <sd_detach>
-
-- Changed to <devfs_*register_chrdev> in drivers/char/tty_io.c
-
-- Ported to kernel 2.2.7
-===============================================================================
-Changes for patch v99
-
-- Ported to kernel 2.2.8
-
-- Fixed bug in drivers/scsi/sd.c when >16 SCSI discs
-
-- Disable warning messages when unable to read partition table for
-  removable media
-===============================================================================
-Changes for patch v100
-
-- Ported to kernel 2.3.1-pre5
-
-- Added "oops-on-panic" boot option
-
-- Improved debugging in <devfs_register> and <devfs_unregister>
-
-- Register entry in <sr_detect>
-
-- Unregister entry in <sr_detach>
-
-- Register entry in <sg_detect>
-
-- Unregister entry in <sg_detach>
-
-- Added support for ALSA drivers
-===============================================================================
-Changes for patch v101
-
-- Ported to kernel 2.3.2
-===============================================================================
-Changes for patch v102
-
-- Update serial driver to register PCMCIA entries
-  Thanks to Roch-Alexandre Nomine-Beguin <roch@samarkand.infini.fr>
-
-- Updated an email address in ChangeLog
-
-- Hide virtual console capture entries from directory listings when
-  corresponding console device is not open
-===============================================================================
-Changes for patch v103
-
-- Ported to kernel 2.3.3
-===============================================================================
-Changes for patch v104
-
-- Added documentation for some functions
-
-- Added "doc" target to fs/devfs/Makefile
-
-- Added "v4l" directory for video4linux devices
-
-- Replaced call to <devfs_unregister> in <sd_detach> with call to
-  <devfs_register_partitions>
-
-- Moved registration for sr and sg drivers from detect() to attach()
-  methods
-
-- Register entries in <st_attach> and unregister in <st_detach>
-
-- Work around IDE driver treating CD-ROM as gendisk
-
-- Use <sed> instead of <tr> in rc.devfs
-
-- Updated ToDo list
-
-- Removed "oops-on-panic" boot option: now always Oops
-===============================================================================
-Changes for patch v105
-
-- Unregister SCSI host from <scsi_host_no_list> in <scsi_unregister>
-  Thanks to Zoltán Böszörményi <zboszor@mail.externet.hu>
-
-- Don't save /dev/log in rc.devfs
-
-- Ported to kernel 2.3.4-pre1
-===============================================================================
-Changes for patch v106
-
-- Fixed silly typo in drivers/scsi/st.c
-
-- Improved debugging in <devfs_register>
-===============================================================================
-Changes for patch v107
-
-- Added "diunlink" and "nokmod" boot options
-
-- Removed superfluous warning message in <devfs_d_iput>
-===============================================================================
-Changes for patch v108
-
-- Remove entries when unloading sound module
-===============================================================================
-Changes for patch v109
-
-- Ported to kernel 2.3.6-pre2
-===============================================================================
-Changes for patch v110
-
-- Took account of change to <d_alloc_root>
-===============================================================================
-Changes for patch v111
-
-- Created separate event queue for each mounted devfs
-
-- Removed <devfs_invalidate_dcache>
-
-- Created new ioctl()s for devfsd
-
-- Incremented devfsd protocol revision to 3
-
-- Fixed bug when re-creating directories: contents were lost
-
-- Block access to inodes until devfsd updates permissions
-===============================================================================
-Changes for patch v112
-
-- Modified patch so it applies against 2.3.5 and 2.3.6
-
-- Updated an email address in ChangeLog
-
-- Do not automatically change ownership/protection of /dev/tty<n>
-
-- Updated sample modules.conf
-
-- Switched to sending process uid/gid to devfsd
-
-- Renamed <call_kmod> to <try_modload>
-
-- Added DEVFSD_NOTIFY_LOOKUP event
-
-- Added DEVFSD_NOTIFY_CHANGE event
-
-- Added DEVFSD_NOTIFY_CREATE event
-
-- Incremented devfsd protocol revision to 4
-
-- Moved kernel-specific stuff to include/linux/devfs_fs_kernel.h
-===============================================================================
-Changes for patch v113
-
-- Ported to kernel 2.3.9
-
-- Restricted permissions on some block devices
-===============================================================================
-Changes for patch v114
-
-- Added support for /dev/netlink
-  Thanks to Dennis Hou <smilax@mindmeld.yi.org>
-
-- Return EISDIR rather than EINVAL for read(2) on directories
-
-- Ported to kernel 2.3.10
-===============================================================================
-Changes for patch v115
-
-- Added support for all remaining character devices
-  Thanks to Dennis Hou <smilax@mindmeld.yi.org>
-
-- Cleaned up netlink support
-===============================================================================
-Changes for patch v116
-
-- Added support for /dev/parport%d
-  Thanks to Tim Waugh <tim@cyberelk.demon.co.uk>
-
-- Fixed parallel port ATAPI tape driver
-
-- Fixed Atari SLM laser printer driver
-===============================================================================
-Changes for patch v117
-
-- Added support for COSA card
-  Thanks to Dennis Hou <smilax@mindmeld.yi.org>
-
-- Fixed drivers/char/ppdev.c: missing #include <linux/init.h>
-
-- Fixed drivers/char/ftape/zftape/zftape-init.c
-  Thanks to Vladimir Popov <mashgrad@usa.net>
-===============================================================================
-Changes for patch v118
-
-- Ported to kernel 2.3.15-pre3
-
-- Fixed bug in loop driver
-
-- Unregister /dev/lp%d entries in drivers/char/lp.c
-  Thanks to Maciej W. Rozycki <macro@ds2.pg.gda.pl>
-===============================================================================
-Changes for patch v119
-
-- Ported to kernel 2.3.16
-===============================================================================
-Changes for patch v120
-
-- Fixed bug in drivers/scsi/scsi.c
-
-- Added /dev/ppp
-  Thanks to Dennis Hou <smilax@mindmeld.yi.org>
-
-- Ported to kernel 2.3.17
-===============================================================================
-Changes for patch v121
-
-- Fixed bug in drivers/block/loop.c
-
-- Ported to kernel 2.3.18
-===============================================================================
-Changes for patch v122
-
-- Ported to kernel 2.3.19
-===============================================================================
-Changes for patch v123
-
-- Ported to kernel 2.3.20
-===============================================================================
-Changes for patch v124
-
-- Ported to kernel 2.3.21
-===============================================================================
-Changes for patch v125
-
-- Created <devfs_get_info>, <devfs_set_info>,
-  <devfs_get_first_child> and <devfs_get_next_sibling>
-  Added <<dir>> parameter to <devfs_register>, <devfs_mk_compat>,
-  <devfs_mk_dir> and <devfs_find_handle>
-  Work sponsored by SGI
-
-- Fixed apparent bug in COSA driver
-
-- Re-instated "scsihosts=" boot option
-===============================================================================
-Changes for patch v126
-
-- Always create /dev/pts if CONFIG_UNIX98_PTYS=y
-
-- Fixed call to <devfs_mk_dir> in drivers/block/ide-disk.c
-  Thanks to Dennis Hou <smilax@mindmeld.yi.org>
-
-- Allow multiple unregistrations
-
-- Created /dev/scsi hierarchy
-  Work sponsored by SGI
-===============================================================================
-Changes for patch v127
-
-Work sponsored by SGI
-
-- No longer disable devpts if devfs enabled (caveat emptor)
-
-- Added flags array to struct gendisk and removed code from
-  drivers/scsi/sd.c
-
-- Created /dev/discs hierarchy
-===============================================================================
-Changes for patch v128
-
-Work sponsored by SGI
-
-- Created /dev/cdroms hierarchy
-===============================================================================
-Changes for patch v129
-
-Work sponsored by SGI
-
-- Removed compatibility entries for sound devices
-
-- Removed compatibility entries for printer devices
-
-- Removed compatibility entries for video4linux devices
-
-- Removed compatibility entries for parallel port devices
-
-- Removed compatibility entries for frame buffer devices
-===============================================================================
-Changes for patch v130
-
-Work sponsored by SGI
-
-- Added major and minor number to devfsd protocol
-
-- Incremented devfsd protocol revision to 5
-
-- Removed compatibility entries for SoundBlaster CD-ROMs
-
-- Removed compatibility entries for netlink devices
-
-- Removed compatibility entries for SCSI generic devices
-
-- Removed compatibility entries for SCSI tape devices
-===============================================================================
-Changes for patch v131
-
-Work sponsored by SGI
-
-- Support info pointer for all devfs entry types
-
-- Added <<info>> parameter to <devfs_mk_dir> and <devfs_mk_symlink>
-
-- Removed /dev/st hierarchy
-
-- Removed /dev/sg hierarchy
-
-- Removed compatibility entries for loop devices
-
-- Removed compatibility entries for IDE tape devices
-
-- Removed compatibility entries for SCSI CD-ROMs
-
-- Removed /dev/sr hierarchy
-===============================================================================
-Changes for patch v132
-
-Work sponsored by SGI
-
-- Removed compatibility entries for floppy devices
-
-- Removed compatibility entries for RAMDISCs
-
-- Removed compatibility entries for meta-devices
-
-- Removed compatibility entries for SCSI discs
-
-- Created <devfs_make_root>
-
-- Removed /dev/sd hierarchy
-
-- Support "../" when searching devfs namespace
-
-- Created /dev/ide/host* hierarchy
-
-- Supported IDE hard discs in /dev/ide/host* hierarchy
-
-- Removed compatibility entries for IDE discs
-
-- Removed /dev/ide/hd hierarchy
-
-- Supported IDE CD-ROMs in /dev/ide/host* hierarchy
-
-- Removed compatibility entries for IDE CD-ROMs
-
-- Removed /dev/ide/cd hierarchy
-===============================================================================
-Changes for patch v133
-
-Work sponsored by SGI
-
-- Created <devfs_get_unregister_slave>
-
-- Fixed bug in fs/partitions/check.c when rescanning
-===============================================================================
-Changes for patch v134
-
-Work sponsored by SGI
-
-- Removed /dev/sd, /dev/sr, /dev/st and /dev/sg directories
-
-- Removed /dev/ide/hd directory
-
-- Exported <devfs_get_parent>
-
-- Created <devfs_register_tape> and /dev/tapes hierarchy
-
-- Removed /dev/ide/mt hierarchy
-
-- Removed /dev/ide/fd hierarchy
-
-- Ported to kernel 2.3.25
-===============================================================================
-Changes for patch v135
-
-Work sponsored by SGI
-
-- Removed compatibility entries for virtual console capture devices
-
-- Removed unused <devfs_set_symlink_destination>
-
-- Removed compatibility entries for serial devices
-
-- Removed compatibility entries for console devices
-
-- Do not hide entries from devfsd or children
-
-- Removed DEVFS_FL_TTY_COMPAT flag
-
-- Removed "nottycompat" boot option
-
-- Removed <devfs_mk_compat>
-===============================================================================
-Changes for patch v136
-
-Work sponsored by SGI
-
-- Moved BSD pty devices to /dev/pty
-
-- Added DEVFS_FL_WAIT flag
-===============================================================================
-Changes for patch v137
-
-Work sponsored by SGI
-
-- Really fixed bug in fs/partitions/check.c when rescanning
-
-- Support new "disc" naming scheme in <get_removable_partition>
-
-- Allow NULL fops in <devfs_register>
-
-- Removed redundant name functions in SCSI disc and IDE drivers
-===============================================================================
-Changes for patch v138
-
-Work sponsored by SGI
-
-- Fixed old bugs in drivers/block/paride/pt.c, drivers/char/tpqic02.c,
-  drivers/net/wan/cosa.c and drivers/scsi/scsi.c
-  Thanks to Sergey Kubushin <ksi@ksi-linux.com>
-
-- Fall back to major table if NULL fops given to <devfs_register>
-===============================================================================
-Changes for patch v139
-
-Work sponsored by SGI
-
-- Corrected and moved <get_blkfops> and <get_chrfops> declarations
-  from arch/alpha/kernel/osf_sys.c to include/linux/fs.h
-
-- Removed name function from struct gendisk
-
-- Updated devfs FAQ
-===============================================================================
-Changes for patch v140
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.27
-===============================================================================
-Changes for patch v141
-
-Work sponsored by SGI
-
-- Bug fix in arch/m68k/atari/joystick.c
-
-- Moved ISDN and capi devices to /dev/isdn
-===============================================================================
-Changes for patch v142
-
-Work sponsored by SGI
-
-- Bug fix in drivers/block/ide-probe.c (patch confusion)
-===============================================================================
-Changes for patch v143
-
-Work sponsored by SGI
-
-- Bug fix in drivers/block/blkpg.c:partition_name()
-===============================================================================
-Changes for patch v144
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.29
-
-- Removed calls to <devfs_register> from cdu31a, cm206, mcd and mcdx
-  CD-ROM drivers: generic driver handles this now
-
-- Moved joystick devices to /dev/joysticks
-===============================================================================
-Changes for patch v145
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.30-pre3
-
-- Register whole-disc entry even for invalid partition tables
-
-- Fixed bug in mounting root FS when initrd enabled
-
-- Fixed device entry leak with IDE CD-ROMs
-
-- Fixed compile problem with drivers/isdn/isdn_common.c
-
-- Moved COSA devices to /dev/cosa
-
-- Support fifos when unregistering
-
-- Created <devfs_register_series> and used in many drivers
-
-- Moved Coda devices to /dev/coda
-
-- Moved parallel port IDE tapes to /dev/pt
-
-- Moved parallel port IDE generic devices to /dev/pg
-===============================================================================
-Changes for patch v146
-
-Work sponsored by SGI
-
-- Removed obsolete DEVFS_FL_COMPAT and DEVFS_FL_TOLERANT flags
-
-- Fixed compile problem with fs/coda/psdev.c
-
-- Reinstate change to <devfs_register_blkdev> in
-  drivers/block/ide-probe.c now that fs/isofs/inode.c is fixed
-
-- Switched to <devfs_register_blkdev> in drivers/block/floppy.c,
-  drivers/scsi/sr.c and drivers/block/md.c
-
-- Moved DAC960 devices to /dev/dac960
-===============================================================================
-Changes for patch v147
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.32-pre4
-===============================================================================
-Changes for patch v148
-
-Work sponsored by SGI
-
-- Removed kmod support: use devfsd instead
-
-- Moved miscellaneous character devices to /dev/misc
-===============================================================================
-Changes for patch v149
-
-Work sponsored by SGI
-
-- Ensure include/linux/joystick.h is OK for user-space
-
-- Improved debugging in <get_vfs_inode>
-
-- Ensure dentries created by devfsd will be cleaned up
-===============================================================================
-Changes for patch v150
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.34
-===============================================================================
-Changes for patch v151
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.35-pre1
-
-- Created <devfs_get_name>
-===============================================================================
-Changes for patch v152
-
-Work sponsored by SGI
-
-- Updated sample modules.conf
-
-- Ported to kernel 2.3.36-pre1
-===============================================================================
-Changes for patch v153
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.42
-
-- Removed <devfs_fill_file>
-===============================================================================
-Changes for patch v154
-
-Work sponsored by SGI
-
-- Took account of device number changes for /dev/fb*
-===============================================================================
-Changes for patch v155
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.43-pre8
-
-- Moved /dev/tty0 to /dev/vc/0
-
-- Moved sequence number formatting from <_tty_make_name> to drivers
-===============================================================================
-Changes for patch v156
-
-Work sponsored by SGI
-
-- Fixed breakage in drivers/scsi/sd.c due to recent SCSI changes
-===============================================================================
-Changes for patch v157
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.45
-===============================================================================
-Changes for patch v158
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.46-pre2
-===============================================================================
-Changes for patch v159
-
-Work sponsored by SGI
-
-- Fixed drivers/block/md.c
-  Thanks to Mike Galbraith <mikeg@weiden.de>
-
-- Documentation fixes
-
-- Moved device registration from <lp_init> to <lp_register>
-  Thanks to Tim Waugh <twaugh@redhat.com>
-===============================================================================
-Changes for patch v160
-
-Work sponsored by SGI
-
-- Fixed drivers/char/joystick/joystick.c
-  Thanks to Vojtech Pavlik <vojtech@suse.cz>
-
-- Documentation updates
-
-- Fixed arch/i386/kernel/mtrr.c if procfs and devfs not enabled
-
-- Fixed drivers/char/stallion.c
-===============================================================================
-Changes for patch v161
-
-Work sponsored by SGI
-
-- Remove /dev/ide when ide-mod is unloaded
-
-- Fixed bug in drivers/block/ide-probe.c when secondary but no primary
-
-- Added DEVFS_FL_NO_PERSISTENCE flag
-
-- Used new DEVFS_FL_NO_PERSISTENCE flag for Unix98 pty slaves
-
-- Removed unnecessary call to <update_devfs_inode_from_entry> in
-  <devfs_readdir>
-
-- Only set auto-ownership for /dev/pty/s*
-===============================================================================
-Changes for patch v162
-
-Work sponsored by SGI
-
-- Set inode->i_size to correct size for symlinks
-  Thanks to Jeremy Fitzhardinge <jeremy@goop.org>
-
-- Only give lookup() method to directories to comply with new VFS
-  assumptions
-
-- Remove unnecessary tests in symlink methods
-
-- Don't kill existing block ops in <devfs_read_inode>
-
-- Restore auto-ownership for /dev/pty/m*
-===============================================================================
-Changes for patch v163
-
-Work sponsored by SGI
-
-- Don't create missing directories in <devfs_find_handle>
-
-- Removed Documentation/filesystems/devfs/mk-devlinks
-
-- Updated Documentation/filesystems/devfs/README
-===============================================================================
-Changes for patch v164
-
-Work sponsored by SGI
-
-- Fixed CONFIG_DEVFS breakage in drivers/char/serial.c introduced in
-  linux-2.3.99-pre6-7
-===============================================================================
-Changes for patch v165
-
-Work sponsored by SGI
-
-- Ported to kernel 2.3.99-pre6
-===============================================================================
-Changes for patch v166
-
-Work sponsored by SGI
-
-- Added CONFIG_DEVFS_MOUNT
-===============================================================================
-Changes for patch v167
-
-Work sponsored by SGI
-
-- Updated Documentation/filesystems/devfs/README
-
-- Updated sample modules.conf
-===============================================================================
-Changes for patch v168
-
-Work sponsored by SGI
-
-- Disabled multi-mount capability (use VFS bindings instead)
-
-- Updated README from master HTML file
-===============================================================================
-Changes for patch v169
-
-Work sponsored by SGI
-
-- Removed multi-mount code
-
-- Removed compatibility macros: VFS has changed too much
-===============================================================================
-Changes for patch v170
-
-Work sponsored by SGI
-
-- Updated README from master HTML file
-
-- Merged devfs inode into devfs entry
-===============================================================================
-Changes for patch v171
-
-Work sponsored by SGI
-
-- Updated sample modules.conf
-
-- Removed dead code in <devfs_register> which used to call
-  <free_dentries>
-
-- Ported to kernel 2.4.0-test2-pre3
-===============================================================================
-Changes for patch v172
-
-Work sponsored by SGI
-
-- Changed interface to <devfs_register>
-
-- Changed interface to <devfs_register_series>
-===============================================================================
-Changes for patch v173
-
-Work sponsored by SGI
-
-- Simplified interface to <devfs_mk_symlink>
-
-- Simplified interface to <devfs_mk_dir>
-
-- Simplified interface to <devfs_find_handle>
-===============================================================================
-Changes for patch v174
-
-Work sponsored by SGI
-
-- Updated README from master HTML file
-===============================================================================
-Changes for patch v175
-
-Work sponsored by SGI
-
-- DocBook update for fs/devfs/base.c
-  Thanks to Tim Waugh <twaugh@redhat.com>
-
-- Removed stale fs/tunnel.c (was never used or completed)
-===============================================================================
-Changes for patch v176
-
-Work sponsored by SGI
-
-- Updated ToDo list
-
-- Removed sample modules.conf: now distributed with devfsd
-
-- Updated README from master HTML file
-
-- Ported to kernel 2.4.0-test3-pre4 (which had devfs-patch-v174)
-===============================================================================
-Changes for patch v177
-
-- Updated README from master HTML file
-
-- Documentation cleanups
-
-- Ensure <devfs_generate_path> terminates string for root entry
-  Thanks to Tim Jansen <tim@tjansen.de>
-
-- Exported <devfs_get_name> to modules
-
-- Make <devfs_mk_symlink> send events to devfsd
-
-- Cleaned up option processing in <devfs_setup>
-
-- Fixed bugs in handling symlinks: could leak or cause Oops
-
-- Cleaned up directory handling by separating fops
-  Thanks to Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk>
-===============================================================================
-Changes for patch v178
-
-- Fixed handling of inverted options in <devfs_setup>
-===============================================================================
-Changes for patch v179
-
-- Adjusted <try_modload> to account for <devfs_generate_path> fix
-===============================================================================
-Changes for patch v180
-
-- Fixed !CONFIG_DEVFS_FS stub declaration of <devfs_get_info>
-===============================================================================
-Changes for patch v181
-
-- Answered question posed by Al Viro and removed his comments from <devfs_open>
-
-- Moved setting of registered flag after other fields are changed
-
-- Fixed race between <devfsd_close> and <devfsd_notify_one>
-
-- Global VFS changes added bogus BKL to devfsd_close(): removed
-
-- Widened locking in <devfs_readlink> and <devfs_follow_link>
-
-- Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc
-
-- Simplified locking in <devfsd_ioctl> and fixed memory leak
-===============================================================================
-Changes for patch v182
-
-- Created <devfs_*alloc_major> and <devfs_*alloc_devnum>
-
-- Removed broken devnum allocation and use <devfs_alloc_devnum>
-
-- Fixed old devnum leak by calling new <devfs_dealloc_devnum>
-
-- Created <devfs_*alloc_unique_number>
-
-- Fixed number leak for /dev/cdroms/cdrom%d
-
-- Fixed number leak for /dev/discs/disc%d
-===============================================================================
-Changes for patch v183
-
-- Fixed bug in <devfs_setup> which could hang boot process
-===============================================================================
-Changes for patch v184
-
-- Documentation typo fix for fs/devfs/util.c
-
-- Fixed drivers/char/stallion.c for devfs
-
-- Added DEVFSD_NOTIFY_DELETE event
-
-- Updated README from master HTML file
-
-- Removed #include <asm/segment.h> from fs/devfs/base.c
-===============================================================================
-Changes for patch v185
-
-- Made <block_semaphore> and <char_semaphore> in fs/devfs/util.c
-  private
-
-- Fixed inode table races by removing it and using inode->u.generic_ip
-  instead
-
-- Moved <devfs_read_inode> into <get_vfs_inode>
-
-- Moved <devfs_write_inode> into <devfs_notify_change>
-===============================================================================
-Changes for patch v186
-
-- Fixed race in <devfs_do_symlink> for uni-processor
-
-- Updated README from master HTML file
-===============================================================================
-Changes for patch v187
-
-- Fixed drivers/char/stallion.c for devfs
-
-- Fixed drivers/char/rocket.c for devfs
-
-- Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers
-===============================================================================
-Changes for patch v188
-
-- Updated major masks in fs/devfs/util.c up to Linus' "no new majors"
-  proclamation. Block: were 126 now 122 free, char: were 26 now 19 free
-
-- Updated README from master HTML file
-
-- Removed remnant of multi-mount support in <devfs_mknod>
-
-- Removed unused DEVFS_FL_SHOW_UNREG flag
-===============================================================================
-Changes for patch v189
-
-- Removed nlink field from struct devfs_inode
-
-- Removed auto-ownership for /dev/pty/* (BSD ptys) and used
-  DEVFS_FL_CURRENT_OWNER|DEVFS_FL_NO_PERSISTENCE for /dev/pty/s* (just
-  like Unix98 pty slaves) and made /dev/pty/m* rw-rw-rw- access
-===============================================================================
-Changes for patch v190
-
-- Updated README from master HTML file
-
-- Replaced BKL with global rwsem to protect symlink data (quick and
-  dirty hack)
-===============================================================================
-Changes for patch v191
-
-- Replaced global rwsem for symlink with per-link refcount
-===============================================================================
-Changes for patch v192
-
-- Removed unnecessary #ifdef CONFIG_DEVFS_FS from arch/i386/kernel/mtrr.c
-
-- Ported to kernel 2.4.10-pre11
-
-- Set inode->i_mapping->a_ops for block nodes in <get_vfs_inode>
-===============================================================================
-Changes for patch v193
-
-- Went back to global rwsem for symlinks (refcount scheme no good)
-===============================================================================
-Changes for patch v194
-
-- Fixed overrun in <devfs_link> by removing function (not needed)
-
-- Updated README from master HTML file
-===============================================================================
-Changes for patch v195
-
-- Fixed buffer underrun in <try_modload>
-
-- Moved down_read() from <search_for_entry_in_dir> to <find_entry>
-===============================================================================
-Changes for patch v196
-
-- Fixed race in <devfsd_ioctl> when setting event mask
-  Thanks to Kari Hurtta <hurtta@leija.mh.fmi.fi>
-
-- Avoid deadlock in <devfs_follow_link> by using temporary buffer
-===============================================================================
-Changes for patch v197
-
-- First release of new locking code for devfs core (v1.0)
-
-- Fixed bug in drivers/cdrom/cdrom.c
-===============================================================================
-Changes for patch v198
-
-- Discard temporary buffer, now use "%s" for dentry names
-
-- Don't generate path in <try_modload>: use fake entry instead
-
-- Use "existing" directory in <_devfs_make_parent_for_leaf>
-
-- Use slab cache rather than fixed buffer for devfsd events
-===============================================================================
-Changes for patch v199
-
-- Removed obsolete usage of DEVFS_FL_NO_PERSISTENCE
-
-- Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>
-
-- Fixed locking bug in <devfs_d_revalidate_wait> due to typo
-
-- Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from devfsd
-  or children
-===============================================================================
-Changes for patch v200
-
-- Ported to kernel 2.5.1-pre2
-===============================================================================
-Changes for patch v201
-
-- Fixed bug in <devfsd_read>: was dereferencing freed pointer
-===============================================================================
-Changes for patch v202
-
-- Fixed bug in <devfsd_close>: was dereferencing freed pointer
-
-- Added process group check for devfsd privileges
-===============================================================================
-Changes for patch v203
-
-- Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>
-===============================================================================
-Changes for patch v204
-
-- Removed long obsolete rc.devfs
-
-- Return old entry in <devfs_mk_dir> for 2.4.x kernels
-
-- Updated README from master HTML file
-
-- Increment refcount on module in <check_disc_changed>
-
-- Created <devfs_get_handle> and exported <devfs_put>
-
-- Increment refcount on module in <devfs_get_ops>
-
-- Created <devfs_put_ops> and used where needed to fix races
-
-- Added clarifying comments in response to preliminary EMC code review
-
-- Added poisoning to <devfs_put>
-
-- Improved debugging messages
-
-- Fixed unregister bugs in drivers/md/lvm-fs.c
-===============================================================================
-Changes for patch v205
-
-- Corrected (made useful) debugging message in <unregister>
-
-- Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs>
-
-- Fixed drivers/md/lvm-fs.c to create "lvm" entry
-
-- Added magic number to guard against scribbling drivers
-
-- Only return old entry in <devfs_mk_dir> if a directory
-
-- Defined macros for error and debug messages
-
-- Updated README from master HTML file
-===============================================================================
-Changes for patch v206
-
-- Added support for multiple Compaq cpqarray controllers
-
-- Fixed (rare, old) race in <devfs_lookup>
-===============================================================================
-Changes for patch v207
-
-- Fixed deadlock bug in <devfs_d_revalidate_wait>
-
-- Tag VFS deletable in <devfs_mk_symlink> if handle ignored
-
-- Updated README from master HTML file
-===============================================================================
-Changes for patch v208
-
-- Added KERN_* to remaining messages
-
-- Cleaned up declaration of <stat_read>
-
-- Updated README from master HTML file
-===============================================================================
-Changes for patch v209
-
-- Updated README from master HTML file
-
-- Removed silently introduced calls to lock_kernel() and
-  unlock_kernel() due to recent VFS locking changes. BKL isn't
-  required in devfs 
-
-- Changed <devfs_rmdir> to allow later additions if not yet empty
-
-- Added calls to <devfs_register_partitions> in drivers/block/blkpc.c
-  <add_partition> and <del_partition>
-
-- Fixed bug in <devfs_alloc_unique_number>: was clearing beyond
-  bitfield
-
-- Fixed bitfield data type for <devfs_*alloc_devnum>
-
-- Made major bitfield type and initialiser 64 bit safe
-===============================================================================
-Changes for patch v210
-
-- Updated fs/devfs/util.c to fix shift warning on 64 bit machines
-  Thanks to Anton Blanchard <anton@samba.org>
-
-- Updated README from master HTML file
-===============================================================================
-Changes for patch v211
-
-- Do not put miscellaneous character devices in /dev/misc if they
-  specify their own directory (i.e. contain a '/' character)
-
-- Copied macro for error messages from fs/devfs/base.c to
-  fs/devfs/util.c and made use of this macro
-
-- Removed 2.4.x compatibility code from fs/devfs/base.c
-===============================================================================
-Changes for patch v212
-
-- Added BKL to <devfs_open> because drivers still need it
-===============================================================================
-Changes for patch v213
-
-- Protected <scan_dir_for_removable> and <get_removable_partition>
-  from changing directory contents
-===============================================================================
-Changes for patch v214
-
-- Switched to ISO C structure field initialisers
-
-- Switch to set_current_state() and move before add_wait_queue()
-
-- Updated README from master HTML file
-
-- Fixed devfs entry leak in <devfs_readdir> when *readdir fails
-===============================================================================
-Changes for patch v215
-
-- Created <devfs_find_and_unregister>
-
-- Switched many functions from <devfs_find_handle> to
-  <devfs_find_and_unregister>
-
-- Switched many functions from <devfs_find_handle> to <devfs_get_handle>
-===============================================================================
-Changes for patch v216
-
-- Switched arch/ia64/sn/io/hcl.c from <devfs_find_handle> to
-  <devfs_get_handle>
-
-- Removed deprecated <devfs_find_handle>
-===============================================================================
-Changes for patch v217
-
-- Exported <devfs_find_and_unregister> and <devfs_only> to modules
-
-- Updated README from master HTML file
-
-- Fixed module unload race in <devfs_open>
-===============================================================================
-Changes for patch v218
-
-- Removed DEVFS_FL_AUTO_OWNER flag
-
-- Switched lingering structure field initialiser to ISO C
-
-- Added locking when setting/clearing flags
-
-- Documentation fix in fs/devfs/util.c
diff --git a/Documentation/filesystems/devfs/README b/Documentation/filesystems/devfs/README
deleted file mode 100644 (file)
index aabfba2..0000000
+++ /dev/null
@@ -1,1959 +0,0 @@
-Devfs (Device File System) FAQ
-
-
-Linux Devfs (Device File System) FAQ
-Richard Gooch
-20-AUG-2002
-
-
-Document languages:
-
-
-
-
-
-
-
------------------------------------------------------------------------------
-
-NOTE: the master copy of this document is available online at:
-
-http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html
-and looks much better than the text version distributed with the
-kernel sources. A mirror site is available at:
-
-http://www.ras.ucalgary.ca/~rgooch/linux/docs/devfs.html
-
-There is also an optional daemon that may be used with devfs. You can
-find out more about it at:
-
-http://www.atnf.csiro.au/~rgooch/linux/
-
-A mailing list is available which you may subscribe to. Send
-email
-to majordomo@oss.sgi.com with the following line in the
-body of the message:
-subscribe devfs
-To unsubscribe, send the message body:
-unsubscribe devfs
-instead. The list is archived at
-
-http://oss.sgi.com/projects/devfs/archive/.
-
------------------------------------------------------------------------------
-
-Contents
-
-
-What is it?
-
-Why do it?
-
-Who else does it?
-
-How it works
-
-Operational issues (essential reading)
-
-Instructions for the impatient
-Permissions persistence across reboots
-Dealing with drivers without devfs support
-All the way with Devfs
-Other Issues
-Kernel Naming Scheme
-Devfsd Naming Scheme
-Old Compatibility Names
-SCSI Host Probing Issues
-
-
-
-Device drivers currently ported
-
-Allocation of Device Numbers
-
-Questions and Answers
-
-Making things work
-Alternatives to devfs
-What I don't like about devfs
-How to report bugs
-Strange kernel messages
-Compilation problems with devfsd
-
-
-Other resources
-
-Translations of this document
-
-
------------------------------------------------------------------------------
-
-
-What is it?
-
-Devfs is an alternative to "real" character and block special devices
-on your root filesystem. Kernel device drivers can register devices by
-name rather than major and minor numbers. These devices will appear in
-devfs automatically, with whatever default ownership and
-protection the driver specified. A daemon (devfsd) can be used to
-override these defaults. Devfs has been in the kernel since 2.3.46.
-
-NOTE that devfs is entirely optional. If you prefer the old
-disc-based device nodes, then simply leave CONFIG_DEVFS_FS=n (the
-default). In this case, nothing will change.  ALSO NOTE that if you do
-enable devfs, the defaults are such that full compatibility is
-maintained with the old devices names.
-
-There are two aspects to devfs: one is the underlying device
-namespace, which is a namespace just like any mounted filesystem. The
-other aspect is the filesystem code which provides a view of the
-device namespace. The reason I make a distinction is because devfs
-can be mounted many times, with each mount showing the same device
-namespace. Changes made are global to all mounted devfs filesystems.
-Also, because the devfs namespace exists without any devfs mounts, you
-can easily mount the root filesystem by referring to an entry in the
-devfs namespace.
-
-
-The cost of devfs is a small increase in kernel code size and memory
-usage. About 7 pages of code (some of that in __init sections) and 72
-bytes for each entry in the namespace. A modest system has only a
-couple of hundred device entries, so this costs a few more
-pages. Compare this with the suggestion to put /dev on a <a
-href="#why-faq-ramdisc">ramdisc.
-
-On a typical machine, the cost is under 0.2 percent. On a modest
-system with 64 MBytes of RAM, the cost is under 0.1 percent.  The
-accusations of "bloatware" levelled at devfs are not justified.
-
------------------------------------------------------------------------------
-
-
-Why do it?
-
-There are several problems that devfs addresses. Some of these
-problems are more serious than others (depending on your point of
-view), and some can be solved without devfs. However, the totality of
-these problems really calls out for devfs.
-
-The choice is a patchwork of inefficient user space solutions, which
-are complex and likely to be fragile, or to use a simple and efficient
-devfs which is robust.
-
-There have been many counter-proposals to devfs, all seeking to
-provide some of the benefits without actually implementing devfs. So
-far there has been an absence of code and no proposed alternative has
-been able to provide all the features that devfs does. Further,
-alternative proposals require far more complexity in user-space (and
-still deliver less functionality than devfs). Some people have the
-mantra of reducing "kernel bloat", but don't consider the effects on
-user-space.
-
-A good solution limits the total complexity of kernel-space and
-user-space.
-
-
-Major&minor allocation
-
-The existing scheme requires the allocation of major and minor device
-numbers for each and every device. This means that a central
-co-ordinating authority is required to issue these device numbers
-(unless you're developing a "private" device driver), in order to
-preserve uniqueness. Devfs shifts the burden to a namespace. This may
-not seem like a huge benefit, but actually it is. Since driver authors
-will naturally choose a device name which reflects the functionality
-of the device, there is far less potential for namespace conflict.
-Solving this requires a kernel change.
-
-/dev management
-
-Because you currently access devices through device nodes, these must
-be created by the system administrator. For standard devices you can
-usually find a MAKEDEV programme which creates all these (hundreds!)
-of nodes. This means that changes in the kernel must be reflected by
-changes in the MAKEDEV programme, or else the system administrator
-creates device nodes by hand.
-
-The basic problem is that there are two separate databases of
-major and minor numbers. One is in the kernel and one is in /dev (or
-in a MAKEDEV programme, if you want to look at it that way). This is
-duplication of information, which is not good practice.
-Solving this requires a kernel change.
-
-/dev growth
-
-A typical /dev has over 1200 nodes! Most of these devices simply don't
-exist because the hardware is not available. A huge /dev increases the
-time to access devices (I'm just referring to the dentry lookup times
-and the time taken to read inodes off disc: the next subsection shows
-some more horrors).
-
-An example of how big /dev can grow is if we consider SCSI devices:
-
-host           6  bits  (say up to 64 hosts on a really big machine)
-channel        4  bits  (say up to 16 SCSI buses per host)
-id             4  bits
-lun            3  bits
-partition      6  bits
-TOTAL          23 bits
-
-
-This requires 8 Mega (1024*1024) inodes if we want to store all
-possible device nodes. Even if we scrap everything but id,partition
-and assume a single host adapter with a single SCSI bus and only one
-logical unit per SCSI target (id), that's still 10 bits or 1024
-inodes. Each VFS inode takes around 256 bytes (kernel 2.1.78), so
-that's 256 kBytes of inode storage on disc (assuming real inodes take
-a similar amount of space as VFS inodes). This is actually not so bad,
-because disc is cheap these days. Embedded systems would care about
-256 kBytes of /dev inodes, but you could argue that embedded systems
-would have hand-tuned /dev directories. I've had to do just that on my
-embedded systems, but I would rather just leave it to devfs.
-
-Another issue is the time taken to lookup an inode when first
-referenced. Not only does this take time in scanning through a list in
-memory, but also the seek times to read the inodes off disc.
-This could be solved in user-space using a clever programme which
-scanned the kernel logs and deleted /dev entries which are not
-available and created them when they were available. This programme
-would need to be run every time a new module was loaded, which would
-slow things down a lot.
-
-There is an existing programme called scsidev which will automatically
-create device nodes for SCSI devices. It can do this by scanning files
-in /proc/scsi. Unfortunately, to extend this idea to other device
-nodes would require significant modifications to existing drivers (so
-they too would provide information in /proc). This is a non-trivial
-change (I should know: devfs has had to do something similar). Once
-you go to this much effort, you may as well use devfs itself (which
-also provides this information).  Furthermore, such a system would
-likely be implemented in an ad-hoc fashion, as different drivers will
-provide their information in different ways.
-
-Devfs is much cleaner, because it (naturally) has a uniform mechanism
-to provide this information: the device nodes themselves!
-
-
-Node to driver file_operations translation
-
-There is an important difference between the way disc-based character
-and block nodes and devfs entries make the connection between an entry
-in /dev and the actual device driver.
-
-With the current 8 bit major and minor numbers the connection between
-disc-based c&b nodes and per-major drivers is done through a
-fixed-length table of 128 entries. The various filesystem types set
-the inode operations for c&b nodes to {chr,blk}dev_inode_operations,
-so when a device is opened a few quick levels of indirection bring us
-to the driver file_operations.
-
-For miscellaneous character devices a second step is required: there
-is a scan for the driver entry with the same minor number as the file
-that was opened, and the appropriate minor open method is called. This
-scanning is done *every time* you open a device node. Potentially, you
-may be searching through dozens of misc. entries before you find your
-open method. While not an enormous performance overhead, this does
-seem pointless.
-
-Linux *must* move beyond the 8 bit major and minor barrier,
-somehow. If we simply increase each to 16 bits, then the indexing
-scheme used for major driver lookup becomes untenable, because the
-major tables (one each for character and block devices) would need to
-be 64 k entries long (512 kBytes on x86, 1 MByte for 64 bit
-systems). So we would have to use a scheme like that used for
-miscellaneous character devices, which means the search time goes up
-linearly with the average number of major device drivers on your
-system. Not all "devices" are hardware, some are higher-level drivers
-like KGI, so you can get more "devices" without adding hardware
-You can improve this by creating an ordered (balanced:-)
-binary tree, in which case your search time becomes log(N).
-Alternatively, you can use hashing to speed up the search.
-But why do that search at all if you don't have to? Once again, it
-seems pointless.
-
-Note that devfs doesn't use the major&minor system. For devfs
-entries, the connection is done when you lookup the /dev entry. When
-devfs_register() is called, an internal table is appended which has
-the entry name and the file_operations. If the dentry cache doesn't
-have the /dev entry already, this internal table is scanned to get the
-file_operations, and an inode is created. If the dentry cache already
-has the entry, there is *no lookup time* (other than the dentry scan
-itself, but we can't avoid that anyway, and besides Linux dentries
-cream other OS's which don't have them:-). Furthermore, the number of
-node entries in a devfs is only the number of available device
-entries, not the number of *conceivable* entries. Even if you remove
-unnecessary entries in a disc-based /dev, the number of conceivable
-entries remains the same: you just limit yourself in order to save
-space.
-
-Devfs provides a fast connection between a VFS node and the device
-driver, in a scalable way.
-
-/dev as a system administration tool
-
-Right now /dev contains a list of conceivable devices, most of which I
-don't have. Devfs only shows those devices available on my
-system. This means that listing /dev is a handy way of checking what
-devices are available.
-
-Major&minor size
-
-Existing major and minor numbers are limited to 8 bits each. This is
-now a limiting factor for some drivers, particularly the SCSI disc
-driver, which consumes a single major number. Only 16 discs are
-supported, and each disc may have only 15 partitions. Maybe this isn't
-a problem for you, but some of us are building huge Linux systems with
-disc arrays. With devfs an arbitrary pointer can be associated with
-each device entry, which can be used to give an effective 32 bit
-device identifier (i.e. that's like having a 32 bit minor
-number). Since this is private to the kernel, there are no C library
-compatibility issues which you would have with increasing major and
-minor number sizes. See the section on "Allocation of Device Numbers"
-for details on maintaining compatibility with userspace.
-
-Solving this requires a kernel change.
-
-Since writing this, the kernel has been modified so that the SCSI disc
-driver has more major numbers allocated to it and now supports up to
-128 discs. Since these major numbers are non-contiguous (a result of
-unplanned expansion), the implementation is a little more cumbersome
-than originally.
-
-Just like the changes to IPv4 to fix impending limitations in the
-address space, people find ways around the limitations. In the long
-run, however, solutions like IPv6 or devfs can't be put off forever.
-
-Read-only root filesystem
-
-Having your device nodes on the root filesystem means that you can't
-operate properly with a read-only root filesystem. This is because you
-want to change ownerships and protections of tty devices. Existing
-practice prevents you using a CD-ROM as your root filesystem for a
-*real* system. Sure, you can boot off a CD-ROM, but you can't change
-tty ownerships, so it's only good for installing.
-
-Also, you can't use a shared NFS root filesystem for a cluster of
-discless Linux machines (having tty ownerships changed on a common
-/dev is not good). Nor can you embed your root filesystem in a
-ROM-FS.
-
-You can get around this by creating a RAMDISC at boot time, making
-an ext2 filesystem in it, mounting it somewhere and copying the
-contents of /dev into it, then unmounting it and mounting it over
-/dev.
-
-A devfs is a cleaner way of solving this.
-
-Non-Unix root filesystem
-
-Non-Unix filesystems (such as NTFS) can't be used for a root
-filesystem because they variously don't support character and block
-special files or symbolic links. You can't have a separate disc-based
-or RAMDISC-based filesystem mounted on /dev because you need device
-nodes before you can mount these. Devfs can be mounted without any
-device nodes. Devlinks won't work because symlinks aren't supported.
-An alternative solution is to use initrd to mount a RAMDISC initial
-root filesystem (which is populated with a minimal set of device
-nodes), and then construct a new /dev in another RAMDISC, and finally
-switch to your non-Unix root filesystem. This requires clever boot
-scripts and a fragile and conceptually complex boot procedure.
-
-Devfs solves this in a robust and conceptually simple way.
-
-PTY security
-
-Current pseudo-tty (pty) devices are owned by root and read-writable
-by everyone. The user of a pty-pair cannot change
-ownership/protections without being suid-root.
-
-This could be solved with a secure user-space daemon which runs as
-root and does the actual creation of pty-pairs. Such a daemon would
-require modification to *every* programme that wants to use this new
-mechanism. It also slows down creation of pty-pairs.
-
-An alternative is to create a new open_pty() syscall which does much
-the same thing as the user-space daemon. Once again, this requires
-modifications to pty-handling programmes.
-
-The devfs solution allows a device driver to "tag" certain device
-files so that when an unopened device is opened, the ownerships are
-changed to the current euid and egid of the opening process, and the
-protections are changed to the default registered by the driver. When
-the device is closed ownership is set back to root and protections are
-set back to read-write for everybody. No programme need be changed.
-The devpts filesystem provides this auto-ownership feature for Unix98
-ptys. It doesn't support old-style pty devices, nor does it have all
-the other features of devfs.
-
-Intelligent device management
-
-Devfs implements a simple yet powerful protocol for communication with
-a device management daemon (devfsd) which runs in user space. It is
-possible to send a message (either synchronously or asynchronously) to
-devfsd on any event, such as registration/unregistration of device
-entries, opening and closing devices, looking up inodes, scanning
-directories and more. This has many possibilities. Some of these are
-already implemented. See:
-
-
-http://www.atnf.csiro.au/~rgooch/linux/
-
-Device entry registration events can be used by devfsd to change
-permissions of newly-created device nodes. This is one mechanism to
-control device permissions.
-
-Device entry registration/unregistration events can be used to run
-programmes or scripts. This can be used to provide automatic mounting
-of filesystems when a new block device media is inserted into the
-drive.
-
-Asynchronous device open and close events can be used to implement
-clever permissions management. For example, the default permissions on
-/dev/dsp do not allow everybody to read from the device. This is
-sensible, as you don't want some remote user recording what you say at
-your console. However, the console user is also prevented from
-recording. This behaviour is not desirable. With asynchronous device
-open and close events, you can have devfsd run a programme or script
-when console devices are opened to change the ownerships for *other*
-device nodes (such as /dev/dsp). On closure, you can run a different
-script to restore permissions. An advantage of this scheme over
-modifying the C library tty handling is that this works even if your
-programme crashes (how many times have you seen the utmp database with
-lingering entries for non-existent logins?).
-
-Synchronous device open events can be used to perform intelligent
-device access protections. Before the device driver open() method is
-called, the daemon must first validate the open attempt, by running an
-external programme or script. This is far more flexible than access
-control lists, as access can be determined on the basis of other
-system conditions instead of just the UID and GID.
-
-Inode lookup events can be used to authenticate module autoload
-requests. Instead of using kmod directly, the event is sent to
-devfsd which can implement an arbitrary authentication before loading
-the module itself.
-
-Inode lookup events can also be used to construct arbitrary
-namespaces, without having to resort to populating devfs with symlinks
-to devices that don't exist.
-
-Speculative Device Scanning
-
-Consider an application (like cdparanoia) that wants to find all
-CD-ROM devices on the system (SCSI, IDE and other types), whether or
-not their respective modules are loaded. The application must
-speculatively open certain device nodes (such as /dev/sr0 for the SCSI
-CD-ROMs) in order to make sure the module is loaded. This requires
-that all Linux distributions follow the standard device naming scheme
-(last time I looked RedHat did things differently). Devfs solves the
-naming problem.
-
-The same application also wants to see which devices are actually
-available on the system. With the existing system it needs to read the
-/dev directory and speculatively open each /dev/sr* device to
-determine if the device exists or not. With a large /dev this is an
-inefficient operation, especially if there are many /dev/sr* nodes. A
-solution like scsidev could reduce the number of /dev/sr* entries (but
-of course that also requires all that inefficient directory scanning).
-
-With devfs, the application can open the /dev/sr directory
-(which triggers the module autoloading if required), and proceed to
-read /dev/sr. Since only the available devices will have
-entries, there are no inefficencies in directory scanning or device
-openings.
-
------------------------------------------------------------------------------
-
-Who else does it?
-
-FreeBSD has a devfs implementation. Solaris and AIX each have a
-pseudo-devfs (something akin to scsidev but for all devices, with some
-unspecified kernel support). BeOS, Plan9 and QNX also have it. SGI's
-IRIX 6.4 and above also have a device filesystem.
-
-While we shouldn't just automatically do something because others do
-it, we should not ignore the work of others either. FreeBSD has a lot
-of competent people working on it, so their opinion should not be
-blithely ignored.
-
------------------------------------------------------------------------------
-
-
-How it works
-
-Registering device entries
-
-For every entry (device node) in a devfs-based /dev a driver must call
-devfs_register(). This adds the name of the device entry, the
-file_operations structure pointer and a few other things to an
-internal table. Device entries may be added and removed at any
-time. When a device entry is registered, it automagically appears in
-any mounted devfs'.
-
-Inode lookup
-
-When a lookup operation on an entry is performed and if there is no
-driver information for that entry devfs will attempt to call
-devfsd. If still no driver information can be found then a negative
-dentry is yielded and the next stage operation will be called by the
-VFS (such as create() or mknod() inode methods). If driver information
-can be found, an inode is created (if one does not exist already) and
-all is well.
-
-Manually creating device nodes
-
-The mknod() method allows you to create an ordinary named pipe in the
-devfs, or you can create a character or block special inode if one
-does not already exist. You may wish to create a character or block
-special inode so that you can set permissions and ownership. Later, if
-a device driver registers an entry with the same name, the
-permissions, ownership and times are retained. This is how you can set
-the protections on a device even before the driver is loaded. Once you
-create an inode it appears in the directory listing.
-
-Unregistering device entries
-
-A device driver calls devfs_unregister() to unregister an entry.
-
-Chroot() gaols
-
-2.2.x kernels
-
-The semantics of inode creation are different when devfs is mounted
-with the "explicit" option. Now, when a device entry is registered, it
-will not appear until you use mknod() to create the device. It doesn't
-matter if you mknod() before or after the device is registered with
-devfs_register(). The purpose of this behaviour is to support
-chroot(2) gaols, where you want to mount a minimal devfs inside the
-gaol. Only the devices you specifically want to be available (through
-your mknod() setup) will be accessible.
-
-2.4.x kernels
-
-As of kernel 2.3.99, the VFS has had the ability to rebind parts of
-the global filesystem namespace into another part of the namespace.
-This now works even at the leaf-node level, which means that
-individual files and device nodes may be bound into other parts of the
-namespace. This is like making links, but better, because it works
-across filesystems (unlike hard links) and works through chroot()
-gaols (unlike symbolic links).
-
-Because of these improvements to the VFS, the multi-mount capability
-in devfs is no longer needed. The administrator may create a minimal
-device tree inside a chroot(2) gaol by using VFS bindings. As this
-provides most of the features of the devfs multi-mount capability, I
-removed the multi-mount support code (after issuing an RFC). This
-yielded code size reductions and simplifications.
-
-If you want to construct a minimal chroot() gaol, the following
-command should suffice:
-
-mount --bind /dev/null /gaol/dev/null
-
-
-Repeat for other device nodes you want to expose. Simple!
-
------------------------------------------------------------------------------
-
-
-Operational issues
-
-
-Instructions for the impatient
-
-Nobody likes reading documentation. People just want to get in there
-and play. So this section tells you quickly the steps you need to take
-to run with devfs mounted over /dev. Skip these steps and you will end
-up with a nearly unbootable system. Subsequent sections describe the
-issues in more detail, and discuss non-essential configuration
-options.
-
-Devfsd
-OK, if you're reading this, I assume you want to play with
-devfs. First you should ensure that /usr/src/linux contains a
-recent kernel source tree. Then you need to compile devfsd, the device
-management daemon, available at
-
-http://www.atnf.csiro.au/~rgooch/linux/.
-Because the kernel has a naming scheme
-which is quite different from the old naming scheme, you need to
-install devfsd so that software and configuration files that use the
-old naming scheme will not break.
-
-Compile and install devfsd. You will be provided with a default
-configuration file /etc/devfsd.conf which will provide
-compatibility symlinks for the old naming scheme. Don't change this
-config file unless you know what you're doing. Even if you think you
-do know what you're doing, don't change it until you've followed all
-the steps below and booted a devfs-enabled system and verified that it
-works.
-
-Now edit your main system boot script so that devfsd is started at the
-very beginning (before any filesystem
-checks). /etc/rc.d/rc.sysinit is often the main boot script
-on systems with SysV-style boot scripts. On systems with BSD-style
-boot scripts it is often /etc/rc. Also check
-/sbin/rc.
-
-NOTE that the line you put into the boot
-script should be exactly:
-
-/sbin/devfsd /dev
-
-DO NOT use some special daemon-launching
-programme, otherwise the boot script may not wait for devfsd to finish
-initialising.
-
-System Libraries
-There may still be some problems because of broken software making
-assumptions about device names. In particular, some software does not
-handle devices which are symbolic links. If you are running a libc 5
-based system, install libc 5.4.44 (if you have libc 5.4.46, go back to
-libc 5.4.44, which is actually correct). If you are running a glibc
-based system, make sure you have glibc 2.1.3 or later.
-
-/etc/securetty
-PAM (Pluggable Authentication Modules) is supposed to be a flexible
-mechanism for providing better user authentication and access to
-services. Unfortunately, it's also fragile, complex and undocumented
-(check out RedHat 6.1, and probably other distributions as well). PAM
-has problems with symbolic links. Append the following lines to your
-/etc/securetty file:
-
-vc/1
-vc/2
-vc/3
-vc/4
-vc/5
-vc/6
-vc/7
-vc/8
-
-This will not weaken security. If you have a version of util-linux
-earlier than 2.10.h, please upgrade to 2.10.h or later. If you
-absolutely cannot upgrade, then also append the following lines to
-your /etc/securetty file:
-
-1
-2
-3
-4
-5
-6
-7
-8
-
-This may potentially weaken security by allowing root logins over the
-network (a password is still required, though). However, since there
-are problems with dealing with symlinks, I'm suspicious of the level
-of security offered in any case.
-
-XFree86
-While not essential, it's probably a good idea to upgrade to XFree86
-4.0, as patches went in to make it more devfs-friendly. If you don't,
-you'll probably need to apply the following patch to
-/etc/security/console.perms so that ordinary users can run
-startx. Note that not all distributions have this file (e.g. Debian),
-so if it's not present, don't worry about it.
-
---- /etc/security/console.perms.orig    Sat Apr 17 16:26:47 1999 
-+++ /etc/security/console.perms Fri Feb 25 23:53:55 2000 
-@@ -14,7 +14,7 @@ 
- # man 5 console.perms 
-
- # file classes -- these are regular expressions 
--<console>=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9] 
-+<console>=tty[0-9][0-9]* vc/[0-9][0-9]* :[0-9]\.[0-9] :[0-9] 
-
- # device classes -- these are shell-style globs 
- <floppy>=/dev/fd[0-1]* 
-
-If the patch does not apply, then change the line:
-
-<console>=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9]
-
-with:
-
-<console>=tty[0-9][0-9]* vc/[0-9][0-9]* :[0-9]\.[0-9] :[0-9]
-
-
-Disable devpts
-I've had a report of devpts mounted on /dev/pts not working
-correctly. Since devfs will also manage /dev/pts, there is no
-need to mount devpts as well. You should either edit your
-/etc/fstab so devpts is not mounted, or disable devpts from
-your kernel configuration.
-
-Unsupported drivers
-Not all drivers have devfs support. If you depend on one of these
-drivers, you will need to create a script or tarfile that you can use
-at boot time to create device nodes as appropriate. There is a
-section which describes this. Another
-section lists the drivers which have
-devfs support.
-
-/dev/mouse
-
-Many disributions configure /dev/mouse to be the mouse device
-for XFree86 and GPM. I actually think this is a bad idea, because it
-adds another level of indirection. When looking at a config file, if
-you see /dev/mouse you're left wondering which mouse
-is being referred to. Hence I recommend putting the actual mouse
-device (for example /dev/psaux) into your
-/etc/X11/XF86Config file (and similarly for the GPM
-configuration file).
-
-Alternatively, use the same technique used for unsupported drivers
-described above.
-
-The Kernel
-Finally, you need to make sure devfs is compiled into your kernel. Set
-CONFIG_EXPERIMENTAL=y, CONFIG_DEVFS_FS=y and CONFIG_DEVFS_MOUNT=y by
-using favourite configuration tool (i.e. make config or
-make xconfig) and then make clean and then recompile your kernel and 
-modules. At boot, devfs will be mounted onto /dev.
-
-If you encounter problems booting (for example if you forgot a
-configuration step), you can pass devfs=nomount at the kernel
-boot command line. This will prevent the kernel from mounting devfs at
-boot time onto /dev.
-
-In general, a kernel built with CONFIG_DEVFS_FS=y but without mounting
-devfs onto /dev is completely safe, and requires no
-configuration changes. One exception to take note of is when
-LABEL= directives are used in /etc/fstab. In this
-case you will be unable to boot properly. This is because the
-mount(8) programme uses /proc/partitions as part of
-the volume label search process, and the device names it finds are not
-available, because setting CONFIG_DEVFS_FS=y changes the names in
-/proc/partitions, irrespective of whether devfs is mounted.
-
-Now you've finished all the steps required. You're now ready to boot
-your shiny new kernel. Enjoy.
-
-Changing the configuration
-
-OK, you've now booted a devfs-enabled system, and everything works.
-Now you may feel like changing the configuration (common targets are
-/etc/fstab and /etc/devfsd.conf). Since you have a
-system that works, if you make any changes and it doesn't work, you
-now know that you only have to restore your configuration files to the
-default and it will work again.
-
-
-Permissions persistence across reboots
-
-If you don't use mknod(2) to create a device file, nor use chmod(2) or
-chown(2) to change the ownerships/permissions, the inode ctime will
-remain at 0 (the epoch, 12 am, 1-JAN-1970, GMT). Anything with a ctime
-later than this has had it's ownership/permissions changed. Hence, a
-simple script or programme may be used to tar up all changed inodes,
-prior to shutdown. Although effective, many consider this approach a
-kludge.
-
-A much better approach is to use devfsd to save and restore
-permissions. It may be configured to record changes in permissions and
-will save them in a database (in fact a directory tree), and restore
-these upon boot. This is an efficient method and results in immediate
-saving of current permissions (unlike the tar approach, which saves
-permissions at some unspecified future time).
-
-The default configuration file supplied with devfsd has config entries
-which you may uncomment to enable persistence management.
-
-If you decide to use the tar approach anyway, be aware that tar will
-first unlink(2) an inode before creating a new device node. The
-unlink(2) has the effect of breaking the connection between a devfs
-entry and the device driver. If you use the "devfs=only" boot option,
-you lose access to the device driver, requiring you to reload the
-module. I consider this a bug in tar (there is no real need to
-unlink(2) the inode first).
-
-Alternatively, you can use devfsd to provide more sophisticated
-management of device permissions. You can use devfsd to store
-permissions for whole groups of devices with a single configuration
-entry, rather than the conventional single entry per device entry.
-
-Permissions database stored in mounted-over /dev
-
-If you wish to save and restore your device permissions into the
-disc-based /dev while still mounting devfs onto /dev
-you may do so. This requires a 2.4.x kernel (in fact, 2.3.99 or
-later), which has the VFS binding facility. You need to do the
-following to set this up:
-
-
-
-make sure the kernel does not mount devfs at boot time
-
-
-make sure you have a correct /dev/console entry in your
-root file-system (where your disc-based /dev lives)
-
-create the /dev-state directory
-
-
-add the following lines near the very beginning of your boot
-scripts:
-
-mount --bind /dev /dev-state
-mount -t devfs none /dev
-devfsd /dev
-
-
-
-
-add the following lines to your /etc/devfsd.conf file:
-
-REGISTER       ^pt[sy]         IGNORE
-CREATE         ^pt[sy]         IGNORE
-CHANGE         ^pt[sy]         IGNORE
-DELETE         ^pt[sy]         IGNORE
-REGISTER       .*              COPY    /dev-state/$devname $devpath
-CREATE         .*              COPY    $devpath /dev-state/$devname
-CHANGE         .*              COPY    $devpath /dev-state/$devname
-DELETE         .*              CFUNCTION GLOBAL unlink /dev-state/$devname
-RESTORE                /dev-state
-
-Note that the sample devfsd.conf file contains these lines,
-as well as other sample configurations you may find useful. See the
-devfsd distribution
-
-
-reboot.
-
-
-
-
-Permissions database stored in normal directory
-
-If you are using an older kernel which doesn't support VFS binding,
-then you won't be able to have the permissions database in a
-mounted-over /dev. However, you can still use a regular
-directory to store the database. The sample /etc/devfsd.conf
-file above may still be used. You will need to create the
-/dev-state directory prior to installing devfsd. If you have
-old permissions in /dev, then just copy (or move) the device
-nodes over to the new directory.
-
-Which method is better?
-
-The best method is to have the permissions database stored in the
-mounted-over /dev. This is because you will not need to copy
-device nodes over to /dev-state, and because it allows you to
-switch between devfs and non-devfs kernels, without requiring you to
-copy permissions between /dev-state (for devfs) and
-/dev (for non-devfs).
-
-
-Dealing with drivers without devfs support
-
-Currently, not all device drivers in the kernel have been modified to
-use devfs. Device drivers which do not yet have devfs support will not
-automagically appear in devfs. The simplest way to create device nodes
-for these drivers is to unpack a tarfile containing the required
-device nodes. You can do this in your boot scripts. All your drivers
-will now work as before.
-
-Hopefully for most people devfs will have enough support so that they
-can mount devfs directly over /dev without losing most functionality
-(i.e. losing access to various devices). As of 22-JAN-1998 (devfs
-patch version 10) I am now running this way. All the devices I have
-are available in devfs, so I don't lose anything.
-
-WARNING: if your configuration requires the old-style device names
-(i.e. /dev/hda1 or /dev/sda1), you must install devfsd and configure
-it to maintain compatibility entries. It is almost certain that you
-will require this. Note that the kernel creates a compatibility entry
-for the root device, so you don't need initrd.
-
-Note that you no longer need to mount devpts if you use Unix98 PTYs,
-as devfs can manage /dev/pts itself. This saves you some RAM, as you
-don't need to compile and install devpts. Note that some versions of
-glibc have a bug with Unix98 pty handling on devfs systems. Contact
-the glibc maintainers for a fix. Glibc 2.1.3 has the fix.
-
-Note also that apart from editing /etc/fstab, other things will need
-to be changed if you *don't* install devfsd. Some software (like the X
-server) hard-wire device names in their source. It really is much
-easier to install devfsd so that compatibility entries are created.
-You can then slowly migrate your system to using the new device names
-(for example, by starting with /etc/fstab), and then limiting the
-compatibility entries that devfsd creates.
-
-IF YOU CONFIGURE TO MOUNT DEVFS AT BOOT, MAKE SURE YOU INSTALL DEVFSD
-BEFORE YOU BOOT A DEVFS-ENABLED KERNEL!
-
-Now that devfs has gone into the 2.3.46 kernel, I'm getting a lot of
-reports back. Many of these are because people are trying to run
-without devfsd, and hence some things break. Please just run devfsd if
-things break. I want to concentrate on real bugs rather than
-misconfiguration problems at the moment. If people are willing to fix
-bugs/false assumptions in other code (i.e. glibc, X server) and submit
-that to the respective maintainers, that would be great.
-
-
-All the way with Devfs
-
-The devfs kernel patch creates a rationalised device tree. As stated
-above, if you want to keep using the old /dev naming scheme,
-you just need to configure devfsd appopriately (see the man
-page). People who prefer the old names can ignore this section. For
-those of us who like the rationalised names and an uncluttered
-/dev, read on.
-
-If you don't run devfsd, or don't enable compatibility entry
-management, then you will have to configure your system to use the new
-names. For example, you will then need to edit your
-/etc/fstab to use the new disc naming scheme. If you want to
-be able to boot non-devfs kernels, you will need compatibility
-symlinks in the underlying disc-based /dev pointing back to
-the old-style names for when you boot a kernel without devfs.
-
-You can selectively decide which devices you want compatibility
-entries for. For example, you may only want compatibility entries for
-BSD pseudo-terminal devices (otherwise you'll have to patch you C
-library or use Unix98 ptys instead). It's just a matter of putting in
-the correct regular expression into /dev/devfsd.conf.
-
-There are other choices of naming schemes that you may prefer. For
-example, I don't use the kernel-supplied
-names, because they are too verbose. A common misconception is
-that the kernel-supplied names are meant to be used directly in
-configuration files. This is not the case. They are designed to
-reflect the layout of the devices attached and to provide easy
-classification.
-
-If you like the kernel-supplied names, that's fine. If you don't then
-you should be using devfsd to construct a namespace more to your
-liking. Devfsd has built-in code to construct a
-namespace that is both logical and easy to
-manage. In essence, it creates a convenient abbreviation of the
-kernel-supplied namespace.
-
-You are of course free to build your own namespace. Devfsd has all the
-infrastructure required to make this easy for you. All you need do is
-write a script. You can even write some C code and devfsd can load the
-shared object as a callable extension.
-
-
-Other Issues
-
-The init programme
-Another thing to take note of is whether your init programme
-creates a Unix socket /dev/telinit. Some versions of init
-create /dev/telinit so that the telinit programme can
-communicate with the init process. If you have such a system you need
-to make sure that devfs is mounted over /dev *before* init
-starts. In other words, you can't leave the mounting of devfs to
-/etc/rc, since this is executed after init. Other
-versions of init require a named pipe /dev/initctl
-which must exist *before* init starts. Once again, you need to
-mount devfs and then create the named pipe *before* init
-starts.
-
-The default behaviour now is not to mount devfs onto /dev at
-boot time for 2.3.x and later kernels. You can correct this with the
-"devfs=mount" boot option. This solves any problems with init,
-and also prevents the dreaded:
-
-Cannot open initial console
-
-message. For 2.2.x kernels where you need to apply the devfs patch,
-the default is to mount.
-
-If you have automatic mounting of devfs onto /dev then you
-may need to create /dev/initctl in your boot scripts. The
-following lines should suffice:
-
-mknod /dev/initctl p
-kill -SIGUSR1 1       # tell init that /dev/initctl now exists
-
-Alternatively, if you don't want the kernel to mount devfs onto
-/dev then you could use the following procedure is a
-guideline for how to get around /dev/initctl problems:
-
-# cd /sbin
-# mv init init.real
-# cat > init
-#! /bin/sh
-mount -n -t devfs none /dev
-mknod /dev/initctl p
-exec /sbin/init.real $*
-[control-D]
-# chmod a+x init
-
-Note that newer versions of init create /dev/initctl
-automatically, so you don't have to worry about this.
-
-Module autoloading
-You will need to configure devfsd to enable module
-autoloading. The following lines should be placed in your
-/etc/devfsd.conf file:
-
-LOOKUP .*              MODLOAD
-
-
-As of devfsd-v1.3.10, a generic /etc/modules.devfs
-configuration file is installed, which is used by the MODLOAD
-action. This should be sufficient for most configurations. If you
-require further configuration, edit your /etc/modules.conf
-file. The way module autoloading work with devfs is:
-
-
-a process attempts to lookup a device node (e.g. /dev/fred)
-
-
-if that device node does not exist, the full pathname is passed to
-devfsd as a string
-
-
-devfsd will pass the string to the modprobe programme (provided the
-configuration line shown above is present), and specifies that
-/etc/modules.devfs is the configuration file
-
-
-/etc/modules.devfs includes /etc/modules.conf to
-access local configurations
-
-modprobe will search it's configuration files, looking for an alias
-that translates the pathname into a module name
-
-
-the translated pathname is then used to load the module.
-
-
-If you wanted a lookup of /dev/fred to load the
-mymod module, you would require the following configuration
-line in /etc/modules.conf:
-
-alias    /dev/fred    mymod
-
-The /etc/modules.devfs configuration file provides many such
-aliases for standard device names. If you look closely at this file,
-you will note that some modules require multiple alias configuration
-lines. This is required to support module autoloading for old and new
-device names.
-
-Mounting root off a devfs device
-If you wish to mount root off a devfs device when you pass the
-"devfs=only" boot option, then you need to pass in the
-"root=<device>" option to the kernel when booting. If you use
-LILO, then you must have this in lilo.conf:
-
-append = "root=<device>"
-
-Surprised? Yep, so was I. It turns out if you have (as most people
-do):
-
-root = <device>
-
-
-then LILO will determine the device number of <device> and will
-write that device number into a special place in the kernel image
-before starting the kernel, and the kernel will use that device number
-to mount the root filesystem. So, using the "append" variety ensures
-that LILO passes the root filesystem device as a string, which devfs
-can then use.
-
-Note that this isn't an issue if you don't pass "devfs=only".
-
-TTY issues
-The ttyname(3) function in some versions of the C library makes
-false assumptions about device entries which are symbolic links.  The
-tty(1) programme is one that depends on this function.  I've
-written a patch to libc 5.4.43 which fixes this. This has been
-included in libc 5.4.44 and a similar fix is in glibc 2.1.3.
-
-
-Kernel Naming Scheme
-
-The kernel provides a default naming scheme. This scheme is designed
-to make it easy to search for specific devices or device types, and to
-view the available devices. Some device types (such as hard discs),
-have a directory of entries, making it easy to see what devices of
-that class are available. Often, the entries are symbolic links into a
-directory tree that reflects the topology of available devices. The
-topological tree is useful for finding how your devices are arranged.
-
-Below is a list of the naming schemes for the most common drivers. A
-list of reserved device names is
-available for reference. Please send email to
-rgooch@atnf.csiro.au to obtain an allocation. Please be
-patient (the maintainer is busy). An alternative name may be allocated
-instead of the requested name, at the discretion of the maintainer.
-
-Disc Devices
-
-All discs, whether SCSI, IDE or whatever, are placed under the
-/dev/discs hierarchy:
-
-       /dev/discs/disc0        first disc
-       /dev/discs/disc1        second disc
-
-
-Each of these entries is a symbolic link to the directory for that
-device. The device directory contains:
-
-       disc    for the whole disc
-       part*   for individual partitions
-
-
-CD-ROM Devices
-
-All CD-ROMs, whether SCSI, IDE or whatever, are placed under the
-/dev/cdroms hierarchy:
-
-       /dev/cdroms/cdrom0      first CD-ROM
-       /dev/cdroms/cdrom1      second CD-ROM
-
-
-Each of these entries is a symbolic link to the real device entry for
-that device.
-
-Tape Devices
-
-All tapes, whether SCSI, IDE or whatever, are placed under the
-/dev/tapes hierarchy:
-
-       /dev/tapes/tape0        first tape
-       /dev/tapes/tape1        second tape
-
-
-Each of these entries is a symbolic link to the directory for that
-device. The device directory contains:
-
-       mt                      for mode 0
-       mtl                     for mode 1
-       mtm                     for mode 2
-       mta                     for mode 3
-       mtn                     for mode 0, no rewind
-       mtln                    for mode 1, no rewind
-       mtmn                    for mode 2, no rewind
-       mtan                    for mode 3, no rewind
-
-
-SCSI Devices
-
-To uniquely identify any SCSI device requires the following
-information:
-
-  controller   (host adapter)
-  bus          (SCSI channel)
-  target       (SCSI ID)
-  unit         (Logical Unit Number)
-
-
-All SCSI devices are placed under /dev/scsi (assuming devfs
-is mounted on /dev). Hence, a SCSI device with the following
-parameters: c=1,b=2,t=3,u=4 would appear as:
-
-       /dev/scsi/host1/bus2/target3/lun4       device directory
-
-
-Inside this directory, a number of device entries may be created,
-depending on which SCSI device-type drivers were installed.
-
-See the section on the disc naming scheme to see what entries the SCSI
-disc driver creates.
-
-See the section on the tape naming scheme to see what entries the SCSI
-tape driver creates.
-
-The SCSI CD-ROM driver creates:
-
-       cd
-
-
-The SCSI generic driver creates:
-
-       generic
-
-
-IDE Devices
-
-To uniquely identify any IDE device requires the following
-information:
-
-  controller
-  bus          (aka. primary/secondary)
-  target       (aka. master/slave)
-  unit
-
-
-All IDE devices are placed under /dev/ide, and uses a similar
-naming scheme to the SCSI subsystem.
-
-XT Hard Discs
-
-All XT discs are placed under /dev/xd. The first XT disc has
-the directory /dev/xd/disc0.
-
-TTY devices
-
-The tty devices now appear as:
-
-  New name                   Old-name                   Device Type
-  --------                   --------                   -----------
-  /dev/tts/{0,1,...}         /dev/ttyS{0,1,...}         Serial ports
-  /dev/cua/{0,1,...}         /dev/cua{0,1,...}          Call out devices
-  /dev/vc/0                  /dev/tty                   Current virtual console
-  /dev/vc/{1,2,...}          /dev/tty{1...63}           Virtual consoles
-  /dev/vcc/{0,1,...}         /dev/vcs{1...63}           Virtual consoles
-  /dev/pty/m{0,1,...}        /dev/ptyp??                PTY masters
-  /dev/pty/s{0,1,...}        /dev/ttyp??                PTY slaves
-
-
-RAMDISCS
-
-The RAMDISCS are placed in their own directory, and are named thus:
-
-  /dev/rd/{0,1,2,...}
-
-
-Meta Devices
-
-The meta devices are placed in their own directory, and are named
-thus:
-
-  /dev/md/{0,1,2,...}
-
-
-Floppy discs
-
-Floppy discs are placed in the /dev/floppy directory.
-
-Loop devices
-
-Loop devices are placed in the /dev/loop directory.
-
-Sound devices
-
-Sound devices are placed in the /dev/sound directory
-(audio, sequencer, ...).
-
-
-Devfsd Naming Scheme
-
-Devfsd provides a naming scheme which is a convenient abbreviation of
-the kernel-supplied namespace. In some
-cases, the kernel-supplied naming scheme is quite convenient, so
-devfsd does not provide another naming scheme. The convenience names
-that devfsd creates are in fact the same names as the original devfs
-kernel patch created (before Linus mandated the Big Name
-Change). These are referred to as "new compatibility entries".
-
-In order to configure devfsd to create these convenience names, the
-following lines should be placed in your /etc/devfsd.conf:
-
-REGISTER       .*              MKNEWCOMPAT
-UNREGISTER     .*              RMNEWCOMPAT
-
-This will cause devfsd to create (and destroy) symbolic links which
-point to the kernel-supplied names.
-
-SCSI Hard Discs
-
-All SCSI discs are placed under /dev/sd (assuming devfs is
-mounted on /dev). Hence, a SCSI disc with the following
-parameters: c=1,b=2,t=3,u=4 would appear as:
-
-       /dev/sd/c1b2t3u4        for the whole disc
-       /dev/sd/c1b2t3u4p5      for the 5th partition
-       /dev/sd/c1b2t3u4p5s6    for the 6th slice in the 5th partition
-
-
-SCSI Tapes
-
-All SCSI tapes are placed under /dev/st. A similar naming
-scheme is used as for SCSI discs. A SCSI tape with the
-parameters:c=1,b=2,t=3,u=4 would appear as:
-
-       /dev/st/c1b2t3u4m0      for mode 0
-       /dev/st/c1b2t3u4m1      for mode 1
-       /dev/st/c1b2t3u4m2      for mode 2
-       /dev/st/c1b2t3u4m3      for mode 3
-       /dev/st/c1b2t3u4m0n     for mode 0, no rewind
-       /dev/st/c1b2t3u4m1n     for mode 1, no rewind
-       /dev/st/c1b2t3u4m2n     for mode 2, no rewind
-       /dev/st/c1b2t3u4m3n     for mode 3, no rewind
-
-
-SCSI CD-ROMs
-
-All SCSI CD-ROMs are placed under /dev/sr. A similar naming
-scheme is used as for SCSI discs. A SCSI CD-ROM with the
-parameters:c=1,b=2,t=3,u=4 would appear as:
-
-       /dev/sr/c1b2t3u4
-
-
-SCSI Generic Devices
-
-The generic (aka. raw) interface for all SCSI devices are placed under
-/dev/sg. A similar naming scheme is used as for SCSI discs. A
-SCSI generic device with the parameters:c=1,b=2,t=3,u=4 would appear
-as:
-
-       /dev/sg/c1b2t3u4
-
-
-IDE Hard Discs
-
-All IDE discs are placed under /dev/ide/hd, using a similar
-convention to SCSI discs. The following mappings exist between the new
-and the old names:
-
-       /dev/hda        /dev/ide/hd/c0b0t0u0
-       /dev/hdb        /dev/ide/hd/c0b0t1u0
-       /dev/hdc        /dev/ide/hd/c0b1t0u0
-       /dev/hdd        /dev/ide/hd/c0b1t1u0
-
-
-IDE Tapes
-
-A similar naming scheme is used as for IDE discs. The entries will
-appear in the /dev/ide/mt directory.
-
-IDE CD-ROM
-
-A similar naming scheme is used as for IDE discs. The entries will
-appear in the /dev/ide/cd directory.
-
-IDE Floppies
-
-A similar naming scheme is used as for IDE discs. The entries will
-appear in the /dev/ide/fd directory.
-
-XT Hard Discs
-
-All XT discs are placed under /dev/xd. The first XT disc
-would appear as /dev/xd/c0t0.
-
-
-Old Compatibility Names
-
-The old compatibility names are the legacy device names, such as
-/dev/hda, /dev/sda, /dev/rtc and so on.
-Devfsd can be configured to create compatibility symlinks so that you
-may continue to use the old names in your configuration files and so
-that old applications will continue to function correctly.
-
-In order to configure devfsd to create these legacy names, the
-following lines should be placed in your /etc/devfsd.conf:
-
-REGISTER       .*              MKOLDCOMPAT
-UNREGISTER     .*              RMOLDCOMPAT
-
-This will cause devfsd to create (and destroy) symbolic links which
-point to the kernel-supplied names.
-
-
------------------------------------------------------------------------------
-
-
-Device drivers currently ported
-
-- All miscellaneous character devices support devfs (this is done
-  transparently through misc_register())
-
-- SCSI discs and generic hard discs
-
-- Character memory devices (null, zero, full and so on)
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- Loop devices (/dev/loop?)
-- TTY devices (console, serial ports, terminals and pseudo-terminals)
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- SCSI tapes (/dev/scsi and /dev/tapes)
-
-- SCSI CD-ROMs (/dev/scsi and /dev/cdroms)
-
-- SCSI generic devices (/dev/scsi)
-
-- RAMDISCS (/dev/ram?)
-
-- Meta Devices (/dev/md*)
-
-- Floppy discs (/dev/floppy)
-
-- Parallel port printers (/dev/printers)
-
-- Sound devices (/dev/sound)
-  Thanks to Eric Dumas <dumas@linux.eu.org> and
-  C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- Joysticks (/dev/joysticks)
-
-- Sparc keyboard (/dev/kbd)
-
-- DSP56001 digital signal processor (/dev/dsp56k)
-
-- Apple Desktop Bus (/dev/adb)
-
-- Coda network file system (/dev/cfs*)
-
-- Virtual console capture devices (/dev/vcc)
-  Thanks to Dennis Hou <smilax@mindmeld.yi.org>
-
-- Frame buffer devices (/dev/fb)
-
-- Video capture devices (/dev/v4l)
-
-
------------------------------------------------------------------------------
-
-
-Allocation of Device Numbers
-
-Devfs allows you to write a driver which doesn't need to allocate a
-device number (major&minor numbers) for the internal operation of the
-kernel. However, there are a number of userspace programmes that use
-the device number as a unique handle for a device. An example is the
-find programme, which uses device numbers to determine whether
-an inode is on a different filesystem than another inode. The device
-number used is the one for the block device which a filesystem is
-using. To preserve compatibility with userspace programmes, block
-devices using devfs need to have unique device numbers allocated to
-them. Furthermore, POSIX specifies device numbers, so some kind of
-device number needs to be presented to userspace.
-
-The simplest option (especially when porting drivers to devfs) is to
-keep using the old major and minor numbers. Devfs will take whatever
-values are given for major&minor and pass them onto userspace.
-
-This device number is a 16 bit number, so this leaves plenty of space
-for large numbers of discs and partitions. This scheme can also be
-used for character devices, in particular the tty devices, which are
-currently limited to 256 pseudo-ttys (this limits the total number of
-simultaneous xterms and remote logins).  Note that the device number
-is limited to the range 36864-61439 (majors 144-239), in order to
-avoid any possible conflicts with existing official allocations.
-
-Please note that using dynamically allocated block device numbers may
-break the NFS daemons (both user and kernel mode), which expect dev_t
-for a given device to be constant over the lifetime of remote mounts.
-
-A final note on this scheme: since it doesn't increase the size of
-device numbers, there are no compatibility issues with userspace.
-
------------------------------------------------------------------------------
-
-
-Questions and Answers
-
-
-Making things work
-Alternatives to devfs
-What I don't like about devfs
-How to report bugs
-Strange kernel messages
-Compilation problems with devfsd
-
-
-
-Making things work
-
-Here are some common questions and answers.
-
-
-
-Devfsd doesn't start
-
-Make sure you have compiled and installed devfsd
-Make sure devfsd is being started from your boot
-scripts
-Make sure you have configured your kernel to enable devfs (see
-below)
-Make sure devfs is mounted (see below)
-
-
-Devfsd is not managing all my permissions
-
-Make sure you are capturing the appropriate events. For example,
-device entries created by the kernel generate REGISTER events,
-but those created by devfsd generate CREATE events.
-
-
-Devfsd is not capturing all REGISTER events
-
-See the previous entry: you may need to capture CREATE events.
-
-
-X will not start
-
-Make sure you followed the steps 
-outlined above.
-
-
-Why don't my network devices appear in devfs?
-
-This is not a bug. Network devices have their own, completely separate
-namespace. They are accessed via socket(2) and
-setsockopt(2) calls, and thus require no device nodes. I have
-raised the possibilty of moving network devices into the device
-namespace, but have had no response.
-
-
-How can I test if I have devfs compiled into my kernel?
-
-All filesystems built-in or currently loaded are listed in
-/proc/filesystems. If you see a devfs entry, then
-you know that devfs was compiled into your kernel. If you have
-correctly configured and rebuilt your kernel, then devfs will be
-built-in. If you think you've configured it in, but
-/proc/filesystems doesn't show it, you've made a mistake.
-Common mistakes include:
-
-Using a 2.2.x kernel without applying the devfs patch (if you
-don't know how to patch your kernel, use 2.4.x instead, don't bother
-asking me how to patch)
-Forgetting to set CONFIG_EXPERIMENTAL=y
-Forgetting to set CONFIG_DEVFS_FS=y
-Forgetting to set CONFIG_DEVFS_MOUNT=y (if you want devfs
-to be automatically mounted at boot)
-Editing your .config manually, instead of using make
-config or make xconfig
-Forgetting to run make dep; make clean after changing the
-configuration and before compiling
-Forgetting to compile your kernel and modules
-Forgetting to install your kernel
-Forgetting to install your modules
-
-Please check twice that you've done all these steps before sending in
-a bug report.
-
-
-
-How can I test if devfs is mounted on /dev?
-
-The device filesystem will always create an entry called
-".devfsd", which is used to communicate with the daemon. Even
-if the daemon is not running, this entry will exist. Testing for the
-existence of this entry is the approved method of determining if devfs
-is mounted or not. Note that the type of entry (i.e. regular file,
-character device, named pipe, etc.) may change without notice. Only
-the existence of the entry should be relied upon.
-
-
-When I start devfsd, I see the error:
-Error opening file: ".devfsd"   No such file or directory?
-
-This means that devfs is not mounted. Make sure you have devfs mounted.
-
-
-How do I mount devfs?
-
-First make sure you have devfs compiled into your kernel (see
-above). Then you will either need to:
-
-set CONFIG_DEVFS_MOUNT=y in your kernel config
-pass devfs=mount to your boot loader
-mount devfs manually in your boot scripts with:
-mount -t none devfs /dev
-
-
-
-Mount by volume LABEL=<label> doesn't work with
-devfs
-
-Most probably you are not mounting devfs onto /dev. What
-happens is that if your kernel config has CONFIG_DEVFS_FS=y
-then the contents of /proc/partitions will have the devfs
-names (such as scsi/host0/bus0/target0/lun0/part1). The
-contents of /proc/partitions are used by mount(8) when
-mounting by volume label. If devfs is not mounted on /dev,
-then mount(8) will fail to find devices. The solution is to
-make sure that devfs is mounted on /dev. See above for how to
-do that.
-
-
-I have extra or incorrect entries in /dev
-
-You may have stale entries in your dev-state area. Check for a
-RESTORE configuration line in your devfsd configuration
-(typically /etc/devfsd.conf). If you have this line, check
-the contents of the specified directory for stale entries. Remove
-any entries which are incorrect, then reboot.
-
-
-I get "Unable to open initial console" messages at boot
-
-This usually happens when you don't have devfs automounted onto
-/dev at boot time, and there is no valid
-/dev/console entry on your root file-system. Create a valid
-/dev/console device node.
-
-
-
-
-
-Alternatives to devfs
-
-I've attempted to collate all the anti-devfs proposals and explain
-their limitations. Under construction.
-
-
-Why not just pass device create/remove events to a daemon?
-
-Here the suggestion is to develop an API in the kernel so that devices
-can register create and remove events, and a daemon listens for those
-events. The daemon would then populate/depopulate /dev (which
-resides on disc).
-
-This has several limitations:
-
-
-it only works for modules loaded and unloaded (or devices inserted
-and removed) after the kernel has finished booting. Without a database
-of events, there is no way the daemon could fully populate
-/dev
-
-
-if you add a database to this scheme, the question is then how to
-present that database to user-space. If you make it a list of strings
-with embedded event codes which are passed through a pipe to the
-daemon, then this is only of use to the daemon. I would argue that the
-natural way to present this data is via a filesystem (since many of
-the events will be of a hierarchical nature), such as devfs.
-Presenting the data as a filesystem makes it easy for the user to see
-what is available and also makes it easy to write scripts to scan the
-"database"
-
-
-the tight binding between device nodes and drivers is no longer
-possible (requiring the otherwise perfectly avoidable
-table lookups)
-
-
-you cannot catch inode lookup events on /dev which means
-that module autoloading requires device nodes to be created. This is a
-problem, particularly for drivers where only a few inodes are created
-from a potentially large set
-
-
-this technique can't be used when the root FS is mounted
-read-only
-
-
-
-
-Just implement a better scsidev
-
-This suggestion involves taking the scsidev programme and
-extending it to scan for all devices, not just SCSI devices. The
-scsidev programme works by scanning /proc/scsi
-
-Problems:
-
-
-the kernel does not currently provide a list of all devices
-available. Not all drivers register entries in /proc or
-generate kernel messages
-
-
-there is no uniform mechanism to register devices other than the
-devfs API
-
-
-implementing such an API is then the same as the
-proposal above
-
-
-
-
-Put /dev on a ramdisc
-
-This suggestion involves creating a ramdisc and populating it with
-device nodes and then mounting it over /dev.
-
-Problems:
-
-
-
-this doesn't help when mounting the root filesystem, since you
-still need a device node to do that
-
-
-if you want to use this technique for the root device node as
-well, you need to use initrd. This complicates the booting sequence
-and makes it significantly harder to administer and configure. The
-initrd is essentially opaque, robbing the system administrator of easy
-configuration
-
-
-insufficient information is available to correctly populate the
-ramdisc. So we come back to the
-proposal above to "solve" this
-
-
-a ramdisc-based solution would take more kernel memory, since the
-backing store would be (at best) normal VFS inodes and dentries, which
-take 284 bytes and 112 bytes, respectively, for each entry. Compare
-that to 72 bytes for devfs
-
-
-
-
-Do nothing: there's no problem
-
-Sometimes people can be heard to claim that the existing scheme is
-fine. This is what they're ignoring:
-
-
-device number size (8 bits each for major and minor) is a real
-limitation, and must be fixed somehow. Systems with large numbers of
-SCSI devices, for example, will continue to consume the remaining
-unallocated major numbers. USB will also need to push beyond the 8 bit
-minor limitation
-
-
-simply increasing the device number size is insufficient. Apart
-from causing a lot of pain, it doesn't solve the management issues
-of a /dev with thousands or more device nodes
-
-
-ignoring the problem of a huge /dev will not make it go
-away, and dismisses the legitimacy of a large number of people who
-want a dynamic /dev
-
-
-the standard response then becomes: "write a device management
-daemon", which brings us back to the
-proposal above
-
-
-
-
-What I don't like about devfs
-
-Here are some common complaints about devfs, and some suggestions and
-solutions that may make it more palatable for you. I can't please
-everybody, but I do try :-)
-
-I hate the naming scheme
-
-First, remember that no naming scheme will please everybody. You hate
-the scheme, others love it. Who's to say who's right and who's wrong?
-Ultimately, the person who writes the code gets to choose, and what
-exists now is a combination of the choices made by the
-devfs author and the
-kernel maintainer (Linus).
-
-However, not all is lost. If you want to create your own naming
-scheme, it is a simple matter to write a standalone script, hack
-devfsd, or write a script called by devfsd. You can create whatever
-naming scheme you like.
-
-Further, if you want to remove all traces of the devfs naming scheme
-from /dev, you can mount devfs elsewhere (say
-/devfs) and populate /dev with links into
-/devfs. This population can be automated using devfsd if you
-wish.
-
-You can even use the VFS binding facility to make the links, rather
-than using symbolic links. This way, you don't even have to see the
-"destination" of these symbolic links.
-
-Devfs puts policy into the kernel
-
-There's already policy in the kernel. Device numbers are in fact
-policy (why should the kernel dictate what device numbers I use?).
-Face it, some policy has to be in the kernel. The real difference
-between device names as policy and device numbers as policy is that
-no one will use device numbers directly, because device
-numbers are devoid of meaning to humans and are ugly. At least with
-the devfs device names, (even though you can add your own naming
-scheme) some people will use the devfs-supplied names directly. This
-offends some people :-)
-
-Devfs is bloatware
-
-This is not even remotely true. As shown above,
-both code and data size are quite modest.
-
-
-How to report bugs
-
-If you have (or think you have) a bug with devfs, please follow the
-steps below:
-
-
-
-make sure you have enabled debugging output when configuring your
-kernel. You will need to set (at least) the following config options:
-
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SLAB=y
-
-
-
-please make sure you have the latest devfs patches applied. The
-latest kernel version might not have the latest devfs patches applied
-yet (Linus is very busy)
-
-
-save a copy of your complete kernel logs (preferably by
-using the dmesg programme) for later inclusion in your bug
-report. You may need to use the -s switch to increase the
-internal buffer size so you can capture all the boot messages.
-Don't edit or trim the dmesg output
-
-
-
-
-try booting with devfs=dall passed to the kernel boot
-command line (read the documentation on your bootloader on how to do
-this), and save the result to a file. This may be quite verbose, and
-it may overflow the messages buffer, but try to get as much of it as
-you can
-
-
-send a copy of your devfsd configuration file(s)
-
-send the bug report to me first.
-Don't expect that I will see it if you post it to the linux-kernel
-mailing list. Include all the information listed above, plus
-anything else that you think might be relevant. Put the string
-devfs somewhere in the subject line, so my mail filters mark
-it as urgent
-
-
-
-
-Here is a general guide on how to ask questions in a way that greatly
-improves your chances of getting a reply:
-
-http://www.tuxedo.org/~esr/faqs/smart-questions.html. If you have
-a bug to report, you should also read
-
-http://www.chiark.greenend.org.uk/~sgtatham/bugs.html.
-
-
-Strange kernel messages
-
-You may see devfs-related messages in your kernel logs. Below are some
-messages and what they mean (and what you should do about them, if
-anything).
-
-
-
-devfs_register(fred): could not append to parent, err: -17
-
-You need to check what the error code means, but usually 17 means
-EEXIST. This means that a driver attempted to create an entry
-fred in a directory, but there already was an entry with that
-name. This is often caused by flawed boot scripts which untar a bunch
-of inodes into /dev, as a way to restore permissions. This
-message is harmless, as the device nodes will still
-provide access to the driver (unless you use the devfs=only
-boot option, which is only for dedicated souls:-). If you want to get
-rid of these annoying messages, upgrade to devfsd-v1.3.20 and use the
-recommended RESTORE directive to restore permissions.
-
-
-devfs_mk_dir(bill): using old entry in dir: c1808724 ""
-
-This is similar to the message above, except that a driver attempted
-to create a directory named bill, and the parent directory
-has an entry with the same name. In this case, to ensure that drivers
-continue to work properly, the old entry is re-used and given to the
-driver. In 2.5 kernels, the driver is given a NULL entry, and thus,
-under rare circumstances, may not create the require device nodes.
-The solution is the same as above.
-
-
-
-
-
-Compilation problems with devfsd
-
-Usually, you can compile devfsd just by typing in
-make in the source directory, followed by a make
-install (as root). Sometimes, you may have problems, particularly
-on broken configurations.
-
-
-
-error messages relating to DEVFSD_NOTIFY_DELETE
-
-This happened because you have an ancient set of kernel headers
-installed in /usr/include/linux or /usr/src/linux.
-Install kernel 2.4.10 or later. You may need to pass the
-KERNEL_DIR variable to make (if you did not install
-the new kernel sources as /usr/src/linux), or you may copy
-the devfs_fs.h file in the kernel source tree into
-/usr/include/linux.
-
-
-
-
------------------------------------------------------------------------------
-
-
-Other resources
-
-
-
-Douglas Gilbert has written a useful document at
-
-http://www.torque.net/sg/devfs_scsi.html which
-explores the SCSI subsystem and how it interacts with devfs
-
-
-Douglas Gilbert has written another useful document at
-
-http://www.torque.net/scsi/SCSI-2.4-HOWTO/ which
-discusses the Linux SCSI subsystem in 2.4.
-
-
-Johannes Erdfelt has started a discussion paper on Linux and
-hot-swap devices, describing what the requirements are for a scalable
-solution and how and why he's used devfs+devfsd. Note that this is an
-early draft only, available in plain text form at:
-
-http://johannes.erdfelt.com/hotswap.txt.
-Johannes has promised a HTML version will follow.
-
-
-I presented an invited 
-paper
-at the
-
-2nd Annual Storage Management Workshop held in Miamia, Florida,
-U.S.A. in October 2000.
-
-
-
-
------------------------------------------------------------------------------
-
-
-Translations of this document
-
-This document has been translated into other languages.
-
-
-
-
-The document master (in English) by rgooch@atnf.csiro.au is
-available at
-
-http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html
-
-
-
-A Korean translation by viatoris@nownuri.net is available at
-
-http://your.destiny.pe.kr/devfs/devfs.html
-
-
-
-
------------------------------------------------------------------------------
-Most flags courtesy of ITA's 
-Flags of All Countries
-used with permission. 
diff --git a/Documentation/filesystems/devfs/ToDo b/Documentation/filesystems/devfs/ToDo
deleted file mode 100644 (file)
index afd5a8f..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-               Device File System (devfs) ToDo List
-
-               Richard Gooch <rgooch@atnf.csiro.au>
-
-                             3-JUL-2000
-
-This is a list of things to be done for better devfs support in the
-Linux kernel. If you'd like to contribute to the devfs, please have a
-look at this list for anything that is unallocated. Also, if there are
-items missing (surely), please contact me so I can add them to the
-list (preferably with your name attached to them:-).
-
-
-- >256 ptys
-  Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
-
-- Amiga floppy driver (drivers/block/amiflop.c)
-
-- Atari floppy driver (drivers/block/ataflop.c)
-
-- SWIM3 (Super Woz Integrated Machine 3) floppy driver (drivers/block/swim3.c)
-
-- Amiga ZorroII ramdisc driver (drivers/block/z2ram.c)
-
-- Parallel port ATAPI CD-ROM (drivers/block/paride/pcd.c)
-
-- Parallel port ATAPI floppy (drivers/block/paride/pf.c)
-
-- AP1000 block driver (drivers/ap1000/ap.c, drivers/ap1000/ddv.c)
-
-- Archimedes floppy (drivers/acorn/block/fd1772.c)
-
-- MFM hard drive (drivers/acorn/block/mfmhd.c)
-
-- I2O block device (drivers/message/i2o/i2o_block.c)
-
-- ST-RAM device (arch/m68k/atari/stram.c)
-
-- Raw devices
-
diff --git a/Documentation/filesystems/devfs/boot-options b/Documentation/filesystems/devfs/boot-options
deleted file mode 100644 (file)
index df3d33b..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- auto-fill -*-                                                         */
-
-               Device File System (devfs) Boot Options
-
-               Richard Gooch <rgooch@atnf.csiro.au>
-
-                             18-AUG-2001
-
-
-When CONFIG_DEVFS_DEBUG is enabled, you can pass several boot options
-to the kernel to debug devfs. The boot options are prefixed by
-"devfs=", and are separated by commas. Spaces are not allowed. The
-syntax looks like this:
-
-devfs=<option1>,<option2>,<option3>
-
-and so on. For example, if you wanted to turn on debugging for module
-load requests and device registration, you would do:
-
-devfs=dmod,dreg
-
-You may prefix "no" to any option. This will invert the option.
-
-
-Debugging Options
-=================
-
-These requires CONFIG_DEVFS_DEBUG to be enabled.
-Note that all debugging options have 'd' as the first character. By
-default all options are off. All debugging output is sent to the
-kernel logs. The debugging options do not take effect until the devfs
-version message appears (just prior to the root filesystem being
-mounted).
-
-These are the options:
-
-dmod           print module load requests to <request_module>
-
-dreg           print device register requests to <devfs_register>
-
-dunreg         print device unregister requests to <devfs_unregister>
-
-dchange                print device change requests to <devfs_set_flags>
-
-dilookup       print inode lookup requests
-
-diget          print VFS inode allocations
-
-diunlink       print inode unlinks
-
-dichange       print inode changes
-
-dimknod                print calls to mknod(2)
-
-dall           some debugging turned on
-
-
-Other Options
-=============
-
-These control the default behaviour of devfs. The options are:
-
-mount          mount devfs onto /dev at boot time
-
-only           disable non-devfs device nodes for devfs-capable drivers
index 7de1c80cd719fb69446b464f6dfe310e4024788c..b1b6440237a6ef82fa367fdc4560e7b6d3590eb2 100644 (file)
@@ -67,8 +67,7 @@ initrd adds the following new options:
     as the last process has closed it, all data is freed and /dev/initrd
     can't be opened anymore.
 
-  root=/dev/ram0   (without devfs)
-  root=/dev/rd/0   (with devfs)
+  root=/dev/ram0
 
     initrd is mounted as root, and the normal boot procedure is followed,
     with the RAM disk still mounted as root.
@@ -90,8 +89,7 @@ you're building an install floppy), the root file system creation
 procedure should create the /initrd directory.
 
 If initrd will not be mounted in some cases, its content is still
-accessible if the following device has been created (note that this
-does not work if using devfs):
+accessible if the following device has been created:
 
 # mknod /dev/initrd b 1 250 
 # chmod 400 /dev/initrd
@@ -119,8 +117,7 @@ We'll describe the loopback device method:
     (if space is critical, you may want to use the Minix FS instead of Ext2)
  3) mount the file system, e.g.
     # mount -t ext2 -o loop initrd /mnt
- 4) create the console device (not necessary if using devfs, but it can't
-    hurt to do it anyway):
+ 4) create the console device:
     # mkdir /mnt/dev
     # mknod /mnt/dev/console c 5 1
  5) copy all the files that are needed to properly use the initrd
@@ -152,12 +149,7 @@ have to be given:
 
   root=/dev/ram0 init=/linuxrc rw
 
-if not using devfs, or
-
-  root=/dev/rd/0 init=/linuxrc rw
-
-if using devfs. (rw is only necessary if writing to the initrd file
-system.)
+(rw is only necessary if writing to the initrd file system.)
 
 With LOADLIN, you simply execute
 
@@ -217,9 +209,9 @@ following command:
 # exec chroot . what-follows <dev/console >dev/console 2>&1
 
 Where what-follows is a program under the new root, e.g. /sbin/init
-If the new root file system will be used with devfs and has no valid
-/dev directory, devfs must be mounted before invoking chroot in order to
-provide /dev/console.
+If the new root file system will be used with udev and has no valid
+/dev directory, udev must be initialized before invoking chroot in order
+to provide /dev/console.
 
 Note: implementation details of pivot_root may change with time. In order
 to ensure compatibility, the following points should be observed:
@@ -236,7 +228,7 @@ Now, the initrd can be unmounted and the memory allocated by the RAM
 disk can be freed:
 
 # umount /initrd
-# blockdev --flushbufs /dev/ram0    # /dev/rd/0 if using devfs
+# blockdev --flushbufs /dev/ram0
 
 It is also possible to use initrd with an NFS-mounted root, see the
 pivot_root(8) man page for details.
index 1543802ef53ec8f5ee434fe6c6a63b443e741103..edc04d74ae239e35308081415ea19cd7de9304bf 100644 (file)
@@ -119,7 +119,6 @@ Code        Seq#    Include File            Comments
 'c'    00-7F   linux/comstats.h        conflict!
 'c'    00-7F   linux/coda.h            conflict!
 'd'    00-FF   linux/char/drm/drm/h    conflict!
-'d'    00-1F   linux/devfs_fs.h        conflict!
 'd'    00-DF   linux/video_decoder.h   conflict!
 'd'    F0-FF   linux/digi1.h
 'e'    all     linux/digi1.h           conflict!
index 2e352a605fcfef3a6dcb83d4c875635f9f89a71a..86e9282d1c20053058ef1525b259d2645dd99ad3 100644 (file)
@@ -35,7 +35,6 @@ parameter is applicable:
        APM     Advanced Power Management support is enabled.
        AX25    Appropriate AX.25 support is enabled.
        CD      Appropriate CD support is enabled.
-       DEVFS   devfs support is enabled.
        DRM     Direct Rendering Management support is enabled.
        EDD     BIOS Enhanced Disk Drive Services (EDD) is enabled
        EFI     EFI Partitioning (GPT) is enabled
@@ -440,9 +439,6 @@ running once the system is up.
                        Format: <area>[,<node>]
                        See also Documentation/networking/decnet.txt.
 
-       devfs=          [DEVFS]
-                       See Documentation/filesystems/devfs/boot-options.
-
        dhash_entries=  [KNL]
                        Set number of hash buckets for dentry cache.
 
@@ -1669,6 +1665,10 @@ running once the system is up.
        usbhid.mousepoll=
                        [USBHID] The interval which mice are to be polled at.
 
+       vdso=           [IA-32]
+                       vdso=1: enable VDSO (default)
+                       vdso=0: disable VDSO mapping
+
        video=          [FB] Frame buffer configuration
                        See Documentation/fb/modedb.txt.
 
@@ -1685,9 +1685,14 @@ running once the system is up.
                        decrease the size and leave more room for directly
                        mapped kernel RAM.
 
-       vmhalt=         [KNL,S390]
+       vmhalt=         [KNL,S390] Perform z/VM CP command after system halt.
+                       Format: <command>
+
+       vmpanic=        [KNL,S390] Perform z/VM CP command after kernel panic.
+                       Format: <command>
 
-       vmpoff=         [KNL,S390]
+       vmpoff=         [KNL,S390] Perform z/VM CP command after power off.
+                       Format: <command>
 
        waveartist=     [HW,OSS]
                        Format: <io>,<irq>,<dma>,<dma2>
index 22488d7911681e8b40cf43a93439f550fa0f93dc..c1f64fdf84cba2ba6a9f04fc1d5315da7a732ecc 100644 (file)
@@ -3,16 +3,23 @@
                              ===================
 
 The key request service is part of the key retention service (refer to
-Documentation/keys.txt). This document explains more fully how that the
-requesting algorithm works.
+Documentation/keys.txt).  This document explains more fully how the requesting
+algorithm works.
 
 The process starts by either the kernel requesting a service by calling
-request_key():
+request_key*():
 
        struct key *request_key(const struct key_type *type,
                                const char *description,
                                const char *callout_string);
 
+or:
+
+       struct key *request_key_with_auxdata(const struct key_type *type,
+                                            const char *description,
+                                            const char *callout_string,
+                                            void *aux);
+
 Or by userspace invoking the request_key system call:
 
        key_serial_t request_key(const char *type,
@@ -20,16 +27,26 @@ Or by userspace invoking the request_key system call:
                                 const char *callout_info,
                                 key_serial_t dest_keyring);
 
-The main difference between the two access points is that the in-kernel
-interface does not need to link the key to a keyring to prevent it from being
-immediately destroyed. The kernel interface returns a pointer directly to the
-key, and it's up to the caller to destroy the key.
+The main difference between the access points is that the in-kernel interface
+does not need to link the key to a keyring to prevent it from being immediately
+destroyed.  The kernel interface returns a pointer directly to the key, and
+it's up to the caller to destroy the key.
+
+The request_key_with_auxdata() call is like the in-kernel request_key() call,
+except that it permits auxiliary data to be passed to the upcaller (the default
+is NULL).  This is only useful for those key types that define their own upcall
+mechanism rather than using /sbin/request-key.
 
 The userspace interface links the key to a keyring associated with the process
 to prevent the key from going away, and returns the serial number of the key to
 the caller.
 
 
+The following example assumes that the key types involved don't define their
+own upcall mechanisms.  If they do, then those should be substituted for the
+forking and execution of /sbin/request-key.
+
+
 ===========
 THE PROCESS
 ===========
@@ -40,8 +57,8 @@ A request proceeds in the following manner:
      interface].
 
  (2) request_key() searches the process's subscribed keyrings to see if there's
-     a suitable key there. If there is, it returns the key. If there isn't, and
-     callout_info is not set, an error is returned. Otherwise the process
+     a suitable key there.  If there is, it returns the key.  If there isn't,
+     and callout_info is not set, an error is returned.  Otherwise the process
      proceeds to the next step.
 
  (3) request_key() sees that A doesn't have the desired key yet, so it creates
@@ -62,7 +79,7 @@ A request proceeds in the following manner:
      instantiation.
 
  (7) The program may want to access another key from A's context (say a
-     Kerberos TGT key). It just requests the appropriate key, and the keyring
+     Kerberos TGT key).  It just requests the appropriate key, and the keyring
      search notes that the session keyring has auth key V in its bottom level.
 
      This will permit it to then search the keyrings of process A with the
@@ -79,10 +96,11 @@ A request proceeds in the following manner:
 (10) The program then exits 0 and request_key() deletes key V and returns key
      U to the caller.
 
-This also extends further. If key W (step 7 above) didn't exist, key W would be
-created uninstantiated, another auth key (X) would be created (as per step 3)
-and another copy of /sbin/request-key spawned (as per step 4); but the context
-specified by auth key X will still be process A, as it was in auth key V.
+This also extends further.  If key W (step 7 above) didn't exist, key W would
+be created uninstantiated, another auth key (X) would be created (as per step
+3) and another copy of /sbin/request-key spawned (as per step 4); but the
+context specified by auth key X will still be process A, as it was in auth key
+V.
 
 This is because process A's keyrings can't simply be attached to
 /sbin/request-key at the appropriate places because (a) execve will discard two
@@ -118,17 +136,17 @@ A search of any particular keyring proceeds in the following fashion:
 
  (2) It considers all the non-keyring keys within that keyring and, if any key
      matches the criteria specified, calls key_permission(SEARCH) on it to see
-     if the key is allowed to be found. If it is, that key is returned; if
+     if the key is allowed to be found.  If it is, that key is returned; if
      not, the search continues, and the error code is retained if of higher
      priority than the one currently set.
 
  (3) It then considers all the keyring-type keys in the keyring it's currently
-     searching. It calls key_permission(SEARCH) on each keyring, and if this
+     searching.  It calls key_permission(SEARCH) on each keyring, and if this
      grants permission, it recurses, executing steps (2) and (3) on that
      keyring.
 
 The process stops immediately a valid key is found with permission granted to
-use it. Any error from a previous match attempt is discarded and the key is
+use it.  Any error from a previous match attempt is discarded and the key is
 returned.
 
 When search_process_keyrings() is invoked, it performs the following searches
@@ -153,7 +171,7 @@ The moment one succeeds, all pending errors are discarded and the found key is
 returned.
 
 Only if all these fail does the whole thing fail with the highest priority
-error. Note that several errors may have come from LSM.
+error.  Note that several errors may have come from LSM.
 
 The error priority is:
 
index 61c0fad2fe2fa01ca14b14d218b56282940bafa6..e373f02128434277bc53098185b393df0a7c36d5 100644 (file)
@@ -780,6 +780,17 @@ payload contents" for more information.
     See also Documentation/keys-request-key.txt.
 
 
+(*) To search for a key, passing auxiliary data to the upcaller, call:
+
+       struct key *request_key_with_auxdata(const struct key_type *type,
+                                            const char *description,
+                                            const char *callout_string,
+                                            void *aux);
+
+    This is identical to request_key(), except that the auxiliary data is
+    passed to the key_type->request_key() op if it exists.
+
+
 (*) When it is no longer required, the key should be released using:
 
        void key_put(struct key *key);
@@ -1031,6 +1042,24 @@ The structure has a number of fields, some of which are mandatory:
      as might happen when the userspace buffer is accessed.
 
 
+ (*) int (*request_key)(struct key *key, struct key *authkey, const char *op,
+                       void *aux);
+
+     This method is optional.  If provided, request_key() and
+     request_key_with_auxdata() will invoke this function rather than
+     upcalling to /sbin/request-key to operate upon a key of this type.
+
+     The aux parameter is as passed to request_key_with_auxdata() or is NULL
+     otherwise.  Also passed are the key to be operated upon, the
+     authorisation key for this operation and the operation type (currently
+     only "create").
+
+     This function should return only when the upcall is complete.  Upon return
+     the authorisation key will be revoked, and the target key will be
+     negatively instantiated if it is still uninstantiated.  The error will be
+     returned to the caller of request_key*().
+
+
 ============================
 REQUEST-KEY CALLBACK SERVICE
 ============================
diff --git a/Documentation/pi-futex.txt b/Documentation/pi-futex.txt
new file mode 100644 (file)
index 0000000..5d61dac
--- /dev/null
@@ -0,0 +1,121 @@
+Lightweight PI-futexes
+----------------------
+
+We are calling them lightweight for 3 reasons:
+
+ - in the user-space fastpath a PI-enabled futex involves no kernel work
+   (or any other PI complexity) at all. No registration, no extra kernel
+   calls - just pure fast atomic ops in userspace.
+
+ - even in the slowpath, the system call and scheduling pattern is very
+   similar to normal futexes.
+
+ - the in-kernel PI implementation is streamlined around the mutex
+   abstraction, with strict rules that keep the implementation
+   relatively simple: only a single owner may own a lock (i.e. no
+   read-write lock support), only the owner may unlock a lock, no
+   recursive locking, etc.
+
+Priority Inheritance - why?
+---------------------------
+
+The short reply: user-space PI helps achieving/improving determinism for
+user-space applications. In the best-case, it can help achieve
+determinism and well-bound latencies. Even in the worst-case, PI will
+improve the statistical distribution of locking related application
+delays.
+
+The longer reply:
+-----------------
+
+Firstly, sharing locks between multiple tasks is a common programming
+technique that often cannot be replaced with lockless algorithms. As we
+can see it in the kernel [which is a quite complex program in itself],
+lockless structures are rather the exception than the norm - the current
+ratio of lockless vs. locky code for shared data structures is somewhere
+between 1:10 and 1:100. Lockless is hard, and the complexity of lockless
+algorithms often endangers to ability to do robust reviews of said code.
+I.e. critical RT apps often choose lock structures to protect critical
+data structures, instead of lockless algorithms. Furthermore, there are
+cases (like shared hardware, or other resource limits) where lockless
+access is mathematically impossible.
+
+Media players (such as Jack) are an example of reasonable application
+design with multiple tasks (with multiple priority levels) sharing
+short-held locks: for example, a highprio audio playback thread is
+combined with medium-prio construct-audio-data threads and low-prio
+display-colory-stuff threads. Add video and decoding to the mix and
+we've got even more priority levels.
+
+So once we accept that synchronization objects (locks) are an
+unavoidable fact of life, and once we accept that multi-task userspace
+apps have a very fair expectation of being able to use locks, we've got
+to think about how to offer the option of a deterministic locking
+implementation to user-space.
+
+Most of the technical counter-arguments against doing priority
+inheritance only apply to kernel-space locks. But user-space locks are
+different, there we cannot disable interrupts or make the task
+non-preemptible in a critical section, so the 'use spinlocks' argument
+does not apply (user-space spinlocks have the same priority inversion
+problems as other user-space locking constructs). Fact is, pretty much
+the only technique that currently enables good determinism for userspace
+locks (such as futex-based pthread mutexes) is priority inheritance:
+
+Currently (without PI), if a high-prio and a low-prio task shares a lock
+[this is a quite common scenario for most non-trivial RT applications],
+even if all critical sections are coded carefully to be deterministic
+(i.e. all critical sections are short in duration and only execute a
+limited number of instructions), the kernel cannot guarantee any
+deterministic execution of the high-prio task: any medium-priority task
+could preempt the low-prio task while it holds the shared lock and
+executes the critical section, and could delay it indefinitely.
+
+Implementation:
+---------------
+
+As mentioned before, the userspace fastpath of PI-enabled pthread
+mutexes involves no kernel work at all - they behave quite similarly to
+normal futex-based locks: a 0 value means unlocked, and a value==TID
+means locked. (This is the same method as used by list-based robust
+futexes.) Userspace uses atomic ops to lock/unlock these mutexes without
+entering the kernel.
+
+To handle the slowpath, we have added two new futex ops:
+
+  FUTEX_LOCK_PI
+  FUTEX_UNLOCK_PI
+
+If the lock-acquire fastpath fails, [i.e. an atomic transition from 0 to
+TID fails], then FUTEX_LOCK_PI is called. The kernel does all the
+remaining work: if there is no futex-queue attached to the futex address
+yet then the code looks up the task that owns the futex [it has put its
+own TID into the futex value], and attaches a 'PI state' structure to
+the futex-queue. The pi_state includes an rt-mutex, which is a PI-aware,
+kernel-based synchronization object. The 'other' task is made the owner
+of the rt-mutex, and the FUTEX_WAITERS bit is atomically set in the
+futex value. Then this task tries to lock the rt-mutex, on which it
+blocks. Once it returns, it has the mutex acquired, and it sets the
+futex value to its own TID and returns. Userspace has no other work to
+perform - it now owns the lock, and futex value contains
+FUTEX_WAITERS|TID.
+
+If the unlock side fastpath succeeds, [i.e. userspace manages to do a
+TID -> 0 atomic transition of the futex value], then no kernel work is
+triggered.
+
+If the unlock fastpath fails (because the FUTEX_WAITERS bit is set),
+then FUTEX_UNLOCK_PI is called, and the kernel unlocks the futex on the
+behalf of userspace - and it also unlocks the attached
+pi_state->rt_mutex and thus wakes up any potential waiters.
+
+Note that under this approach, contrary to previous PI-futex approaches,
+there is no prior 'registration' of a PI-futex. [which is not quite
+possible anyway, due to existing ABI properties of pthread mutexes.]
+
+Also, under this scheme, 'robustness' and 'PI' are two orthogonal
+properties of futexes, and all four combinations are possible: futex,
+robust-futex, PI-futex, robust+PI-futex.
+
+More details about priority inheritance can be found in
+Documentation/rtmutex.txt.
index df82d75245a01b5055c6793fa822efe949982a2e..76e8064b8c3a5ccb60e6cbb2f55ad5d455d097b0 100644 (file)
@@ -95,7 +95,7 @@ comparison. If the thread has registered a list, then normally the list
 is empty. If the thread/process crashed or terminated in some incorrect
 way then the list might be non-empty: in this case the kernel carefully
 walks the list [not trusting it], and marks all locks that are owned by
-this thread with the FUTEX_OWNER_DEAD bit, and wakes up one waiter (if
+this thread with the FUTEX_OWNER_DIED bit, and wakes up one waiter (if
 any).
 
 The list is guaranteed to be private and per-thread at do_exit() time,
diff --git a/Documentation/rt-mutex-design.txt b/Documentation/rt-mutex-design.txt
new file mode 100644 (file)
index 0000000..c472ffa
--- /dev/null
@@ -0,0 +1,781 @@
+#
+# Copyright (c) 2006 Steven Rostedt
+# Licensed under the GNU Free Documentation License, Version 1.2
+#
+
+RT-mutex implementation design
+------------------------------
+
+This document tries to describe the design of the rtmutex.c implementation.
+It doesn't describe the reasons why rtmutex.c exists. For that please see
+Documentation/rt-mutex.txt.  Although this document does explain problems
+that happen without this code, but that is in the concept to understand
+what the code actually is doing.
+
+The goal of this document is to help others understand the priority
+inheritance (PI) algorithm that is used, as well as reasons for the
+decisions that were made to implement PI in the manner that was done.
+
+
+Unbounded Priority Inversion
+----------------------------
+
+Priority inversion is when a lower priority process executes while a higher
+priority process wants to run.  This happens for several reasons, and
+most of the time it can't be helped.  Anytime a high priority process wants
+to use a resource that a lower priority process has (a mutex for example),
+the high priority process must wait until the lower priority process is done
+with the resource.  This is a priority inversion.  What we want to prevent
+is something called unbounded priority inversion.  That is when the high
+priority process is prevented from running by a lower priority process for
+an undetermined amount of time.
+
+The classic example of unbounded priority inversion is were you have three
+processes, let's call them processes A, B, and C, where A is the highest
+priority process, C is the lowest, and B is in between. A tries to grab a lock
+that C owns and must wait and lets C run to release the lock. But in the
+meantime, B executes, and since B is of a higher priority than C, it preempts C,
+but by doing so, it is in fact preempting A which is a higher priority process.
+Now there's no way of knowing how long A will be sleeping waiting for C
+to release the lock, because for all we know, B is a CPU hog and will
+never give C a chance to release the lock.  This is called unbounded priority
+inversion.
+
+Here's a little ASCII art to show the problem.
+
+   grab lock L1 (owned by C)
+     |
+A ---+
+        C preempted by B
+          |
+C    +----+
+
+B         +-------->
+                B now keeps A from running.
+
+
+Priority Inheritance (PI)
+-------------------------
+
+There are several ways to solve this issue, but other ways are out of scope
+for this document.  Here we only discuss PI.
+
+PI is where a process inherits the priority of another process if the other
+process blocks on a lock owned by the current process.  To make this easier
+to understand, let's use the previous example, with processes A, B, and C again.
+
+This time, when A blocks on the lock owned by C, C would inherit the priority
+of A.  So now if B becomes runnable, it would not preempt C, since C now has
+the high priority of A.  As soon as C releases the lock, it loses its
+inherited priority, and A then can continue with the resource that C had.
+
+Terminology
+-----------
+
+Here I explain some terminology that is used in this document to help describe
+the design that is used to implement PI.
+
+PI chain - The PI chain is an ordered series of locks and processes that cause
+           processes to inherit priorities from a previous process that is
+           blocked on one of its locks.  This is described in more detail
+           later in this document.
+
+mutex    - In this document, to differentiate from locks that implement
+           PI and spin locks that are used in the PI code, from now on
+           the PI locks will be called a mutex.
+
+lock     - In this document from now on, I will use the term lock when
+           referring to spin locks that are used to protect parts of the PI
+           algorithm.  These locks disable preemption for UP (when
+           CONFIG_PREEMPT is enabled) and on SMP prevents multiple CPUs from
+           entering critical sections simultaneously.
+
+spin lock - Same as lock above.
+
+waiter   - A waiter is a struct that is stored on the stack of a blocked
+           process.  Since the scope of the waiter is within the code for
+           a process being blocked on the mutex, it is fine to allocate
+           the waiter on the process's stack (local variable).  This
+           structure holds a pointer to the task, as well as the mutex that
+           the task is blocked on.  It also has the plist node structures to
+           place the task in the waiter_list of a mutex as well as the
+           pi_list of a mutex owner task (described below).
+
+           waiter is sometimes used in reference to the task that is waiting
+           on a mutex. This is the same as waiter->task.
+
+waiters  - A list of processes that are blocked on a mutex.
+
+top waiter - The highest priority process waiting on a specific mutex.
+
+top pi waiter - The highest priority process waiting on one of the mutexes
+                that a specific process owns.
+
+Note:  task and process are used interchangeably in this document, mostly to
+       differentiate between two processes that are being described together.
+
+
+PI chain
+--------
+
+The PI chain is a list of processes and mutexes that may cause priority
+inheritance to take place.  Multiple chains may converge, but a chain
+would never diverge, since a process can't be blocked on more than one
+mutex at a time.
+
+Example:
+
+   Process:  A, B, C, D, E
+   Mutexes:  L1, L2, L3, L4
+
+   A owns: L1
+           B blocked on L1
+           B owns L2
+                  C blocked on L2
+                  C owns L3
+                         D blocked on L3
+                         D owns L4
+                                E blocked on L4
+
+The chain would be:
+
+   E->L4->D->L3->C->L2->B->L1->A
+
+To show where two chains merge, we could add another process F and
+another mutex L5 where B owns L5 and F is blocked on mutex L5.
+
+The chain for F would be:
+
+   F->L5->B->L1->A
+
+Since a process may own more than one mutex, but never be blocked on more than
+one, the chains merge.
+
+Here we show both chains:
+
+   E->L4->D->L3->C->L2-+
+                       |
+                       +->B->L1->A
+                       |
+                 F->L5-+
+
+For PI to work, the processes at the right end of these chains (or we may
+also call it the Top of the chain) must be equal to or higher in priority
+than the processes to the left or below in the chain.
+
+Also since a mutex may have more than one process blocked on it, we can
+have multiple chains merge at mutexes.  If we add another process G that is
+blocked on mutex L2:
+
+  G->L2->B->L1->A
+
+And once again, to show how this can grow I will show the merging chains
+again.
+
+   E->L4->D->L3->C-+
+                   +->L2-+
+                   |     |
+                 G-+     +->B->L1->A
+                         |
+                   F->L5-+
+
+
+Plist
+-----
+
+Before I go further and talk about how the PI chain is stored through lists
+on both mutexes and processes, I'll explain the plist.  This is similar to
+the struct list_head functionality that is already in the kernel.
+The implementation of plist is out of scope for this document, but it is
+very important to understand what it does.
+
+There are a few differences between plist and list, the most important one
+being that plist is a priority sorted linked list.  This means that the
+priorities of the plist are sorted, such that it takes O(1) to retrieve the
+highest priority item in the list.  Obviously this is useful to store processes
+based on their priorities.
+
+Another difference, which is important for implementation, is that, unlike
+list, the head of the list is a different element than the nodes of a list.
+So the head of the list is declared as struct plist_head and nodes that will
+be added to the list are declared as struct plist_node.
+
+
+Mutex Waiter List
+-----------------
+
+Every mutex keeps track of all the waiters that are blocked on itself. The mutex
+has a plist to store these waiters by priority.  This list is protected by
+a spin lock that is located in the struct of the mutex. This lock is called
+wait_lock.  Since the modification of the waiter list is never done in
+interrupt context, the wait_lock can be taken without disabling interrupts.
+
+
+Task PI List
+------------
+
+To keep track of the PI chains, each process has its own PI list.  This is
+a list of all top waiters of the mutexes that are owned by the process.
+Note that this list only holds the top waiters and not all waiters that are
+blocked on mutexes owned by the process.
+
+The top of the task's PI list is always the highest priority task that
+is waiting on a mutex that is owned by the task.  So if the task has
+inherited a priority, it will always be the priority of the task that is
+at the top of this list.
+
+This list is stored in the task structure of a process as a plist called
+pi_list.  This list is protected by a spin lock also in the task structure,
+called pi_lock.  This lock may also be taken in interrupt context, so when
+locking the pi_lock, interrupts must be disabled.
+
+
+Depth of the PI Chain
+---------------------
+
+The maximum depth of the PI chain is not dynamic, and could actually be
+defined.  But is very complex to figure it out, since it depends on all
+the nesting of mutexes.  Let's look at the example where we have 3 mutexes,
+L1, L2, and L3, and four separate functions func1, func2, func3 and func4.
+The following shows a locking order of L1->L2->L3, but may not actually
+be directly nested that way.
+
+void func1(void)
+{
+       mutex_lock(L1);
+
+       /* do anything */
+
+       mutex_unlock(L1);
+}
+
+void func2(void)
+{
+       mutex_lock(L1);
+       mutex_lock(L2);
+
+       /* do something */
+
+       mutex_unlock(L2);
+       mutex_unlock(L1);
+}
+
+void func3(void)
+{
+       mutex_lock(L2);
+       mutex_lock(L3);
+
+       /* do something else */
+
+       mutex_unlock(L3);
+       mutex_unlock(L2);
+}
+
+void func4(void)
+{
+       mutex_lock(L3);
+
+       /* do something again */
+
+       mutex_unlock(L3);
+}
+
+Now we add 4 processes that run each of these functions separately.
+Processes A, B, C, and D which run functions func1, func2, func3 and func4
+respectively, and such that D runs first and A last.  With D being preempted
+in func4 in the "do something again" area, we have a locking that follows:
+
+D owns L3
+       C blocked on L3
+       C owns L2
+              B blocked on L2
+              B owns L1
+                     A blocked on L1
+
+And thus we have the chain A->L1->B->L2->C->L3->D.
+
+This gives us a PI depth of 4 (four processes), but looking at any of the
+functions individually, it seems as though they only have at most a locking
+depth of two.  So, although the locking depth is defined at compile time,
+it still is very difficult to find the possibilities of that depth.
+
+Now since mutexes can be defined by user-land applications, we don't want a DOS
+type of application that nests large amounts of mutexes to create a large
+PI chain, and have the code holding spin locks while looking at a large
+amount of data.  So to prevent this, the implementation not only implements
+a maximum lock depth, but also only holds at most two different locks at a
+time, as it walks the PI chain.  More about this below.
+
+
+Mutex owner and flags
+---------------------
+
+The mutex structure contains a pointer to the owner of the mutex.  If the
+mutex is not owned, this owner is set to NULL.  Since all architectures
+have the task structure on at least a four byte alignment (and if this is
+not true, the rtmutex.c code will be broken!), this allows for the two
+least significant bits to be used as flags.  This part is also described
+in Documentation/rt-mutex.txt, but will also be briefly described here.
+
+Bit 0 is used as the "Pending Owner" flag.  This is described later.
+Bit 1 is used as the "Has Waiters" flags.  This is also described later
+  in more detail, but is set whenever there are waiters on a mutex.
+
+
+cmpxchg Tricks
+--------------
+
+Some architectures implement an atomic cmpxchg (Compare and Exchange).  This
+is used (when applicable) to keep the fast path of grabbing and releasing
+mutexes short.
+
+cmpxchg is basically the following function performed atomically:
+
+unsigned long _cmpxchg(unsigned long *A, unsigned long *B, unsigned long *C)
+{
+        unsigned long T = *A;
+        if (*A == *B) {
+                *A = *C;
+        }
+        return T;
+}
+#define cmpxchg(a,b,c) _cmpxchg(&a,&b,&c)
+
+This is really nice to have, since it allows you to only update a variable
+if the variable is what you expect it to be.  You know if it succeeded if
+the return value (the old value of A) is equal to B.
+
+The macro rt_mutex_cmpxchg is used to try to lock and unlock mutexes. If
+the architecture does not support CMPXCHG, then this macro is simply set
+to fail every time.  But if CMPXCHG is supported, then this will
+help out extremely to keep the fast path short.
+
+The use of rt_mutex_cmpxchg with the flags in the owner field help optimize
+the system for architectures that support it.  This will also be explained
+later in this document.
+
+
+Priority adjustments
+--------------------
+
+The implementation of the PI code in rtmutex.c has several places that a
+process must adjust its priority.  With the help of the pi_list of a
+process this is rather easy to know what needs to be adjusted.
+
+The functions implementing the task adjustments are rt_mutex_adjust_prio,
+__rt_mutex_adjust_prio (same as the former, but expects the task pi_lock
+to already be taken), rt_mutex_get_prio, and rt_mutex_setprio.
+
+rt_mutex_getprio and rt_mutex_setprio are only used in __rt_mutex_adjust_prio.
+
+rt_mutex_getprio returns the priority that the task should have.  Either the
+task's own normal priority, or if a process of a higher priority is waiting on
+a mutex owned by the task, then that higher priority should be returned.
+Since the pi_list of a task holds an order by priority list of all the top
+waiters of all the mutexes that the task owns, rt_mutex_getprio simply needs
+to compare the top pi waiter to its own normal priority, and return the higher
+priority back.
+
+(Note:  if looking at the code, you will notice that the lower number of
+        prio is returned.  This is because the prio field in the task structure
+        is an inverse order of the actual priority.  So a "prio" of 5 is
+        of higher priority than a "prio" of 10.)
+
+__rt_mutex_adjust_prio examines the result of rt_mutex_getprio, and if the
+result does not equal the task's current priority, then rt_mutex_setprio
+is called to adjust the priority of the task to the new priority.
+Note that rt_mutex_setprio is defined in kernel/sched.c to implement the
+actual change in priority.
+
+It is interesting to note that __rt_mutex_adjust_prio can either increase
+or decrease the priority of the task.  In the case that a higher priority
+process has just blocked on a mutex owned by the task, __rt_mutex_adjust_prio
+would increase/boost the task's priority.  But if a higher priority task
+were for some reason to leave the mutex (timeout or signal), this same function
+would decrease/unboost the priority of the task.  That is because the pi_list
+always contains the highest priority task that is waiting on a mutex owned
+by the task, so we only need to compare the priority of that top pi waiter
+to the normal priority of the given task.
+
+
+High level overview of the PI chain walk
+----------------------------------------
+
+The PI chain walk is implemented by the function rt_mutex_adjust_prio_chain.
+
+The implementation has gone through several iterations, and has ended up
+with what we believe is the best.  It walks the PI chain by only grabbing
+at most two locks at a time, and is very efficient.
+
+The rt_mutex_adjust_prio_chain can be used either to boost or lower process
+priorities.
+
+rt_mutex_adjust_prio_chain is called with a task to be checked for PI
+(de)boosting (the owner of a mutex that a process is blocking on), a flag to
+check for deadlocking, the mutex that the task owns, and a pointer to a waiter
+that is the process's waiter struct that is blocked on the mutex (although this
+parameter may be NULL for deboosting).
+
+For this explanation, I will not mention deadlock detection. This explanation
+will try to stay at a high level.
+
+When this function is called, there are no locks held.  That also means
+that the state of the owner and lock can change when entered into this function.
+
+Before this function is called, the task has already had rt_mutex_adjust_prio
+performed on it.  This means that the task is set to the priority that it
+should be at, but the plist nodes of the task's waiter have not been updated
+with the new priorities, and that this task may not be in the proper locations
+in the pi_lists and wait_lists that the task is blocked on.  This function
+solves all that.
+
+A loop is entered, where task is the owner to be checked for PI changes that
+was passed by parameter (for the first iteration).  The pi_lock of this task is
+taken to prevent any more changes to the pi_list of the task.  This also
+prevents new tasks from completing the blocking on a mutex that is owned by this
+task.
+
+If the task is not blocked on a mutex then the loop is exited.  We are at
+the top of the PI chain.
+
+A check is now done to see if the original waiter (the process that is blocked
+on the current mutex) is the top pi waiter of the task.  That is, is this
+waiter on the top of the task's pi_list.  If it is not, it either means that
+there is another process higher in priority that is blocked on one of the
+mutexes that the task owns, or that the waiter has just woken up via a signal
+or timeout and has left the PI chain.  In either case, the loop is exited, since
+we don't need to do any more changes to the priority of the current task, or any
+task that owns a mutex that this current task is waiting on.  A priority chain
+walk is only needed when a new top pi waiter is made to a task.
+
+The next check sees if the task's waiter plist node has the priority equal to
+the priority the task is set at.  If they are equal, then we are done with
+the loop.  Remember that the function started with the priority of the
+task adjusted, but the plist nodes that hold the task in other processes
+pi_lists have not been adjusted.
+
+Next, we look at the mutex that the task is blocked on. The mutex's wait_lock
+is taken.  This is done by a spin_trylock, because the locking order of the
+pi_lock and wait_lock goes in the opposite direction. If we fail to grab the
+lock, the pi_lock is released, and we restart the loop.
+
+Now that we have both the pi_lock of the task as well as the wait_lock of
+the mutex the task is blocked on, we update the task's waiter's plist node
+that is located on the mutex's wait_list.
+
+Now we release the pi_lock of the task.
+
+Next the owner of the mutex has its pi_lock taken, so we can update the
+task's entry in the owner's pi_list.  If the task is the highest priority
+process on the mutex's wait_list, then we remove the previous top waiter
+from the owner's pi_list, and replace it with the task.
+
+Note: It is possible that the task was the current top waiter on the mutex,
+      in which case the task is not yet on the pi_list of the waiter.  This
+      is OK, since plist_del does nothing if the plist node is not on any
+      list.
+
+If the task was not the top waiter of the mutex, but it was before we
+did the priority updates, that means we are deboosting/lowering the
+task.  In this case, the task is removed from the pi_list of the owner,
+and the new top waiter is added.
+
+Lastly, we unlock both the pi_lock of the task, as well as the mutex's
+wait_lock, and continue the loop again.  On the next iteration of the
+loop, the previous owner of the mutex will be the task that will be
+processed.
+
+Note: One might think that the owner of this mutex might have changed
+      since we just grab the mutex's wait_lock. And one could be right.
+      The important thing to remember is that the owner could not have
+      become the task that is being processed in the PI chain, since
+      we have taken that task's pi_lock at the beginning of the loop.
+      So as long as there is an owner of this mutex that is not the same
+      process as the tasked being worked on, we are OK.
+
+      Looking closely at the code, one might be confused.  The check for the
+      end of the PI chain is when the task isn't blocked on anything or the
+      task's waiter structure "task" element is NULL.  This check is
+      protected only by the task's pi_lock.  But the code to unlock the mutex
+      sets the task's waiter structure "task" element to NULL with only
+      the protection of the mutex's wait_lock, which was not taken yet.
+      Isn't this a race condition if the task becomes the new owner?
+
+      The answer is No!  The trick is the spin_trylock of the mutex's
+      wait_lock.  If we fail that lock, we release the pi_lock of the
+      task and continue the loop, doing the end of PI chain check again.
+
+      In the code to release the lock, the wait_lock of the mutex is held
+      the entire time, and it is not let go when we grab the pi_lock of the
+      new owner of the mutex.  So if the switch of a new owner were to happen
+      after the check for end of the PI chain and the grabbing of the
+      wait_lock, the unlocking code would spin on the new owner's pi_lock
+      but never give up the wait_lock.  So the PI chain loop is guaranteed to
+      fail the spin_trylock on the wait_lock, release the pi_lock, and
+      try again.
+
+      If you don't quite understand the above, that's OK. You don't have to,
+      unless you really want to make a proof out of it ;)
+
+
+Pending Owners and Lock stealing
+--------------------------------
+
+One of the flags in the owner field of the mutex structure is "Pending Owner".
+What this means is that an owner was chosen by the process releasing the
+mutex, but that owner has yet to wake up and actually take the mutex.
+
+Why is this important?  Why can't we just give the mutex to another process
+and be done with it?
+
+The PI code is to help with real-time processes, and to let the highest
+priority process run as long as possible with little latencies and delays.
+If a high priority process owns a mutex that a lower priority process is
+blocked on, when the mutex is released it would be given to the lower priority
+process.  What if the higher priority process wants to take that mutex again.
+The high priority process would fail to take that mutex that it just gave up
+and it would need to boost the lower priority process to run with full
+latency of that critical section (since the low priority process just entered
+it).
+
+There's no reason a high priority process that gives up a mutex should be
+penalized if it tries to take that mutex again.  If the new owner of the
+mutex has not woken up yet, there's no reason that the higher priority process
+could not take that mutex away.
+
+To solve this, we introduced Pending Ownership and Lock Stealing.  When a
+new process is given a mutex that it was blocked on, it is only given
+pending ownership.  This means that it's the new owner, unless a higher
+priority process comes in and tries to grab that mutex.  If a higher priority
+process does come along and wants that mutex, we let the higher priority
+process "steal" the mutex from the pending owner (only if it is still pending)
+and continue with the mutex.
+
+
+Taking of a mutex (The walk through)
+------------------------------------
+
+OK, now let's take a look at the detailed walk through of what happens when
+taking a mutex.
+
+The first thing that is tried is the fast taking of the mutex.  This is
+done when we have CMPXCHG enabled (otherwise the fast taking automatically
+fails).  Only when the owner field of the mutex is NULL can the lock be
+taken with the CMPXCHG and nothing else needs to be done.
+
+If there is contention on the lock, whether it is owned or pending owner
+we go about the slow path (rt_mutex_slowlock).
+
+The slow path function is where the task's waiter structure is created on
+the stack.  This is because the waiter structure is only needed for the
+scope of this function.  The waiter structure holds the nodes to store
+the task on the wait_list of the mutex, and if need be, the pi_list of
+the owner.
+
+The wait_lock of the mutex is taken since the slow path of unlocking the
+mutex also takes this lock.
+
+We then call try_to_take_rt_mutex.  This is where the architecture that
+does not implement CMPXCHG would always grab the lock (if there's no
+contention).
+
+try_to_take_rt_mutex is used every time the task tries to grab a mutex in the
+slow path.  The first thing that is done here is an atomic setting of
+the "Has Waiters" flag of the mutex's owner field.  Yes, this could really
+be false, because if the the mutex has no owner, there are no waiters and
+the current task also won't have any waiters.  But we don't have the lock
+yet, so we assume we are going to be a waiter.  The reason for this is to
+play nice for those architectures that do have CMPXCHG.  By setting this flag
+now, the owner of the mutex can't release the mutex without going into the
+slow unlock path, and it would then need to grab the wait_lock, which this
+code currently holds.  So setting the "Has Waiters" flag forces the owner
+to synchronize with this code.
+
+Now that we know that we can't have any races with the owner releasing the
+mutex, we check to see if we can take the ownership.  This is done if the
+mutex doesn't have a owner, or if we can steal the mutex from a pending
+owner.  Let's look at the situations we have here.
+
+  1) Has owner that is pending
+  ----------------------------
+
+  The mutex has a owner, but it hasn't woken up and the mutex flag
+  "Pending Owner" is set.  The first check is to see if the owner isn't the
+  current task.  This is because this function is also used for the pending
+  owner to grab the mutex.  When a pending owner wakes up, it checks to see
+  if it can take the mutex, and this is done if the owner is already set to
+  itself.  If so, we succeed and leave the function, clearing the "Pending
+  Owner" bit.
+
+  If the pending owner is not current, we check to see if the current priority is
+  higher than the pending owner.  If not, we fail the function and return.
+
+  There's also something special about a pending owner.  That is a pending owner
+  is never blocked on a mutex.  So there is no PI chain to worry about.  It also
+  means that if the mutex doesn't have any waiters, there's no accounting needed
+  to update the pending owner's pi_list, since we only worry about processes
+  blocked on the current mutex.
+
+  If there are waiters on this mutex, and we just stole the ownership, we need
+  to take the top waiter, remove it from the pi_list of the pending owner, and
+  add it to the current pi_list.  Note that at this moment, the pending owner
+  is no longer on the list of waiters.  This is fine, since the pending owner
+  would add itself back when it realizes that it had the ownership stolen
+  from itself.  When the pending owner tries to grab the mutex, it will fail
+  in try_to_take_rt_mutex if the owner field points to another process.
+
+  2) No owner
+  -----------
+
+  If there is no owner (or we successfully stole the lock), we set the owner
+  of the mutex to current, and set the flag of "Has Waiters" if the current
+  mutex actually has waiters, or we clear the flag if it doesn't.  See, it was
+  OK that we set that flag early, since now it is cleared.
+
+  3) Failed to grab ownership
+  ---------------------------
+
+  The most interesting case is when we fail to take ownership. This means that
+  there exists an owner, or there's a pending owner with equal or higher
+  priority than the current task.
+
+We'll continue on the failed case.
+
+If the mutex has a timeout, we set up a timer to go off to break us out
+of this mutex if we failed to get it after a specified amount of time.
+
+Now we enter a loop that will continue to try to take ownership of the mutex, or
+fail from a timeout or signal.
+
+Once again we try to take the mutex.  This will usually fail the first time
+in the loop, since it had just failed to get the mutex.  But the second time
+in the loop, this would likely succeed, since the task would likely be
+the pending owner.
+
+If the mutex is TASK_INTERRUPTIBLE a check for signals and timeout is done
+here.
+
+The waiter structure has a "task" field that points to the task that is blocked
+on the mutex.  This field can be NULL the first time it goes through the loop
+or if the task is a pending owner and had it's mutex stolen.  If the "task"
+field is NULL then we need to set up the accounting for it.
+
+Task blocks on mutex
+--------------------
+
+The accounting of a mutex and process is done with the waiter structure of
+the process.  The "task" field is set to the process, and the "lock" field
+to the mutex.  The plist nodes are initialized to the processes current
+priority.
+
+Since the wait_lock was taken at the entry of the slow lock, we can safely
+add the waiter to the wait_list.  If the current process is the highest
+priority process currently waiting on this mutex, then we remove the
+previous top waiter process (if it exists) from the pi_list of the owner,
+and add the current process to that list.  Since the pi_list of the owner
+has changed, we call rt_mutex_adjust_prio on the owner to see if the owner
+should adjust its priority accordingly.
+
+If the owner is also blocked on a lock, and had its pi_list changed
+(or deadlock checking is on), we unlock the wait_lock of the mutex and go ahead
+and run rt_mutex_adjust_prio_chain on the owner, as described earlier.
+
+Now all locks are released, and if the current process is still blocked on a
+mutex (waiter "task" field is not NULL), then we go to sleep (call schedule).
+
+Waking up in the loop
+---------------------
+
+The schedule can then wake up for a few reasons.
+  1) we were given pending ownership of the mutex.
+  2) we received a signal and was TASK_INTERRUPTIBLE
+  3) we had a timeout and was TASK_INTERRUPTIBLE
+
+In any of these cases, we continue the loop and once again try to grab the
+ownership of the mutex.  If we succeed, we exit the loop, otherwise we continue
+and on signal and timeout, will exit the loop, or if we had the mutex stolen
+we just simply add ourselves back on the lists and go back to sleep.
+
+Note: For various reasons, because of timeout and signals, the steal mutex
+      algorithm needs to be careful. This is because the current process is
+      still on the wait_list. And because of dynamic changing of priorities,
+      especially on SCHED_OTHER tasks, the current process can be the
+      highest priority task on the wait_list.
+
+Failed to get mutex on Timeout or Signal
+----------------------------------------
+
+If a timeout or signal occurred, the waiter's "task" field would not be
+NULL and the task needs to be taken off the wait_list of the mutex and perhaps
+pi_list of the owner.  If this process was a high priority process, then
+the rt_mutex_adjust_prio_chain needs to be executed again on the owner,
+but this time it will be lowering the priorities.
+
+
+Unlocking the Mutex
+-------------------
+
+The unlocking of a mutex also has a fast path for those architectures with
+CMPXCHG.  Since the taking of a mutex on contention always sets the
+"Has Waiters" flag of the mutex's owner, we use this to know if we need to
+take the slow path when unlocking the mutex.  If the mutex doesn't have any
+waiters, the owner field of the mutex would equal the current process and
+the mutex can be unlocked by just replacing the owner field with NULL.
+
+If the owner field has the "Has Waiters" bit set (or CMPXCHG is not available),
+the slow unlock path is taken.
+
+The first thing done in the slow unlock path is to take the wait_lock of the
+mutex.  This synchronizes the locking and unlocking of the mutex.
+
+A check is made to see if the mutex has waiters or not.  On architectures that
+do not have CMPXCHG, this is the location that the owner of the mutex will
+determine if a waiter needs to be awoken or not.  On architectures that
+do have CMPXCHG, that check is done in the fast path, but it is still needed
+in the slow path too.  If a waiter of a mutex woke up because of a signal
+or timeout between the time the owner failed the fast path CMPXCHG check and
+the grabbing of the wait_lock, the mutex may not have any waiters, thus the
+owner still needs to make this check. If there are no waiters than the mutex
+owner field is set to NULL, the wait_lock is released and nothing more is
+needed.
+
+If there are waiters, then we need to wake one up and give that waiter
+pending ownership.
+
+On the wake up code, the pi_lock of the current owner is taken.  The top
+waiter of the lock is found and removed from the wait_list of the mutex
+as well as the pi_list of the current owner.  The task field of the new
+pending owner's waiter structure is set to NULL, and the owner field of the
+mutex is set to the new owner with the "Pending Owner" bit set, as well
+as the "Has Waiters" bit if there still are other processes blocked on the
+mutex.
+
+The pi_lock of the previous owner is released, and the new pending owner's
+pi_lock is taken.  Remember that this is the trick to prevent the race
+condition in rt_mutex_adjust_prio_chain from adding itself as a waiter
+on the mutex.
+
+We now clear the "pi_blocked_on" field of the new pending owner, and if
+the mutex still has waiters pending, we add the new top waiter to the pi_list
+of the pending owner.
+
+Finally we unlock the pi_lock of the pending owner and wake it up.
+
+
+Contact
+-------
+
+For updates on this document, please email Steven Rostedt <rostedt@goodmis.org>
+
+
+Credits
+-------
+
+Author:  Steven Rostedt <rostedt@goodmis.org>
+
+Reviewers:  Ingo Molnar, Thomas Gleixner, Thomas Duetsch, and Randy Dunlap
+
+Updates
+-------
+
+This document was originally written for 2.6.17-rc3-mm1
diff --git a/Documentation/rt-mutex.txt b/Documentation/rt-mutex.txt
new file mode 100644 (file)
index 0000000..243393d
--- /dev/null
@@ -0,0 +1,79 @@
+RT-mutex subsystem with PI support
+----------------------------------
+
+RT-mutexes with priority inheritance are used to support PI-futexes,
+which enable pthread_mutex_t priority inheritance attributes
+(PTHREAD_PRIO_INHERIT). [See Documentation/pi-futex.txt for more details
+about PI-futexes.]
+
+This technology was developed in the -rt tree and streamlined for
+pthread_mutex support.
+
+Basic principles:
+-----------------
+
+RT-mutexes extend the semantics of simple mutexes by the priority
+inheritance protocol.
+
+A low priority owner of a rt-mutex inherits the priority of a higher
+priority waiter until the rt-mutex is released. If the temporarily
+boosted owner blocks on a rt-mutex itself it propagates the priority
+boosting to the owner of the other rt_mutex it gets blocked on. The
+priority boosting is immediately removed once the rt_mutex has been
+unlocked.
+
+This approach allows us to shorten the block of high-prio tasks on
+mutexes which protect shared resources. Priority inheritance is not a
+magic bullet for poorly designed applications, but it allows
+well-designed applications to use userspace locks in critical parts of
+an high priority thread, without losing determinism.
+
+The enqueueing of the waiters into the rtmutex waiter list is done in
+priority order. For same priorities FIFO order is chosen. For each
+rtmutex, only the top priority waiter is enqueued into the owner's
+priority waiters list. This list too queues in priority order. Whenever
+the top priority waiter of a task changes (for example it timed out or
+got a signal), the priority of the owner task is readjusted. [The
+priority enqueueing is handled by "plists", see include/linux/plist.h
+for more details.]
+
+RT-mutexes are optimized for fastpath operations and have no internal
+locking overhead when locking an uncontended mutex or unlocking a mutex
+without waiters. The optimized fastpath operations require cmpxchg
+support. [If that is not available then the rt-mutex internal spinlock
+is used]
+
+The state of the rt-mutex is tracked via the owner field of the rt-mutex
+structure:
+
+rt_mutex->owner holds the task_struct pointer of the owner. Bit 0 and 1
+are used to keep track of the "owner is pending" and "rtmutex has
+waiters" state.
+
+ owner         bit1    bit0
+ NULL          0       0       mutex is free (fast acquire possible)
+ NULL          0       1       invalid state
+ NULL          1       0       Transitional state*
+ NULL          1       1       invalid state
+ taskpointer   0       0       mutex is held (fast release possible)
+ taskpointer   0       1       task is pending owner
+ taskpointer   1       0       mutex is held and has waiters
+ taskpointer   1       1       task is pending owner and mutex has waiters
+
+Pending-ownership handling is a performance optimization:
+pending-ownership is assigned to the first (highest priority) waiter of
+the mutex, when the mutex is released. The thread is woken up and once
+it starts executing it can acquire the mutex. Until the mutex is taken
+by it (bit 0 is cleared) a competing higher priority thread can "steal"
+the mutex which puts the woken up thread back on the waiters list.
+
+The pending-ownership optimization is especially important for the
+uninterrupted workflow of high-prio tasks which repeatedly
+takes/releases locks that have lower-prio waiters. Without this
+optimization the higher-prio thread would ping-pong to the lower-prio
+task [because at unlock time we always assign a new owner].
+
+(*) The "mutex has waiters" bit gets set to take the lock. If the lock
+doesn't already have an owner, this bit is quickly cleared if there are
+no waiters.  So this is a transitional state to synchronize with looking
+at the owner field of the mutex and the mutex owner releasing the lock.
index 87d76a5c73d05742c0532d702819111681730af9..f61af23dd85d727c9b802ee0b61af99f3230d23f 100644 (file)
@@ -472,6 +472,22 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     The power-management is supported.
 
+  Module snd-darla20
+  ------------------
+
+    Module for Echoaudio Darla20
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
+  Module snd-darla24
+  ------------------
+
+    Module for Echoaudio Darla24
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
   Module snd-dt019x
   -----------------
 
@@ -499,6 +515,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     The power-management is supported.
 
+  Module snd-echo3g
+  -----------------
+
+    Module for Echoaudio 3G cards (Gina3G/Layla3G)
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
   Module snd-emu10k1
   ------------------
 
@@ -657,6 +681,22 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     
     The power-management is supported.
 
+  Module snd-gina20
+  -----------------
+
+    Module for Echoaudio Gina20
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
+  Module snd-gina24
+  -----------------
+
+    Module for Echoaudio Gina24
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
   Module snd-gusclassic
   ---------------------
 
@@ -760,12 +800,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          basic         fixed pin assignment w/o SPDIF
          auto          auto-config reading BIOS (default)
 
-       ALC882/883/885
+       ALC882/885
          3stack-dig    3-jack with SPDIF I/O
          6stck-dig     6-jack digital with SPDIF I/O
          auto          auto-config reading BIOS (default)
 
-       ALC861
+       ALC883/888
+         3stack-dig    3-jack with SPDIF I/O
+         6stack-dig    6-jack digital with SPDIF I/O
+         6stack-dig-demo  6-stack digital for Intel demo board
+         auto          auto-config reading BIOS (default)
+
+       ALC861/660
          3stack        3-jack
          3stack-dig    3-jack with SPDIF I/O
          6stack-dig    6-jack with SPDIF I/O
@@ -937,6 +983,30 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          driver isn't configured properly or you want to try another
          type for testing.
 
+  Module snd-indigo
+  -----------------
+
+    Module for Echoaudio Indigo
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
+  Module snd-indigodj
+  -------------------
+
+    Module for Echoaudio Indigo DJ
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
+  Module snd-indigoio
+  -------------------
+
+    Module for Echoaudio Indigo IO
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
   Module snd-intel8x0
   -------------------
 
@@ -1036,6 +1106,22 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     This module supports multiple cards.
 
+  Module snd-layla20
+  ------------------
+
+    Module for Echoaudio Layla20
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
+  Module snd-layla24
+  ------------------
+
+    Module for Echoaudio Layla24
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
   Module snd-maestro3
   -------------------
 
@@ -1056,6 +1142,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     The power-management is supported.
 
+  Module snd-mia
+  ---------------
+
+    Module for Echoaudio Mia
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
   Module snd-miro
   ---------------
 
@@ -1088,6 +1182,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     When no hotplug fw loader is available, you need to load the
     firmware via mixartloader utility in alsa-tools package.
 
+  Module snd-mona
+  ---------------
+
+    Module for Echoaudio Mona
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
   Module snd-mpu401
   -----------------
 
diff --git a/Documentation/video4linux/README.pvrusb2 b/Documentation/video4linux/README.pvrusb2
new file mode 100644 (file)
index 0000000..c73a32c
--- /dev/null
@@ -0,0 +1,212 @@
+
+$Id$
+Mike Isely <isely@pobox.com>
+
+                           pvrusb2 driver
+
+Background:
+
+  This driver is intended for the "Hauppauge WinTV PVR USB 2.0", which
+  is a USB 2.0 hosted TV Tuner.  This driver is a work in progress.
+  Its history started with the reverse-engineering effort by Björn
+  Danielsson <pvrusb2@dax.nu> whose web page can be found here:
+
+    http://pvrusb2.dax.nu/
+
+  From there Aurelien Alleaume <slts@free.fr> began an effort to
+  create a video4linux compatible driver.  I began with Aurelien's
+  last known snapshot and evolved the driver to the state it is in
+  here.
+
+  More information on this driver can be found at:
+
+    http://www.isely.net/pvrusb2.html
+
+
+  This driver has a strong separation of layers.  They are very
+  roughly:
+
+  1a. Low level wire-protocol implementation with the device.
+
+  1b. I2C adaptor implementation and corresponding I2C client drivers
+      implemented elsewhere in V4L.
+
+  1c. High level hardware driver implementation which coordinates all
+      activities that ensure correct operation of the device.
+
+  2.  A "context" layer which manages instancing of driver, setup,
+      tear-down, arbitration, and interaction with high level
+      interfaces appropriately as devices are hotplugged in the
+      system.
+
+  3.  High level interfaces which glue the driver to various published
+      Linux APIs (V4L, sysfs, maybe DVB in the future).
+
+  The most important shearing layer is between the top 2 layers.  A
+  lot of work went into the driver to ensure that any kind of
+  conceivable API can be laid on top of the core driver.  (Yes, the
+  driver internally leverages V4L to do its work but that really has
+  nothing to do with the API published by the driver to the outside
+  world.)  The architecture allows for different APIs to
+  simultaneously access the driver.  I have a strong sense of fairness
+  about APIs and also feel that it is a good design principle to keep
+  implementation and interface isolated from each other.  Thus while
+  right now the V4L high level interface is the most complete, the
+  sysfs high level interface will work equally well for similar
+  functions, and there's no reason I see right now why it shouldn't be
+  possible to produce a DVB high level interface that can sit right
+  alongside V4L.
+
+  NOTE: Complete documentation on the pvrusb2 driver is contained in
+  the html files within the doc directory; these are exactly the same
+  as what is on the web site at the time.  Browse those files
+  (especially the FAQ) before asking questions.
+
+
+Building
+
+  To build these modules essentially amounts to just running "Make",
+  but you need the kernel source tree nearby and you will likely also
+  want to set a few controlling environment variables first in order
+  to link things up with that source tree.  Please see the Makefile
+  here for comments that explain how to do that.
+
+
+Source file list / functional overview:
+
+  (Note: The term "module" used below generally refers to loosely
+  defined functional units within the pvrusb2 driver and bears no
+  relation to the Linux kernel's concept of a loadable module.)
+
+  pvrusb2-audio.[ch] - This is glue logic that resides between this
+    driver and the msp3400.ko I2C client driver (which is found
+    elsewhere in V4L).
+
+  pvrusb2-context.[ch] - This module implements the context for an
+    instance of the driver.  Everything else eventually ties back to
+    or is otherwise instanced within the data structures implemented
+    here.  Hotplugging is ultimately coordinated here.  All high level
+    interfaces tie into the driver through this module.  This module
+    helps arbitrate each interface's access to the actual driver core,
+    and is designed to allow concurrent access through multiple
+    instances of multiple interfaces (thus you can for example change
+    the tuner's frequency through sysfs while simultaneously streaming
+    video through V4L out to an instance of mplayer).
+
+  pvrusb2-debug.h - This header defines a printk() wrapper and a mask
+    of debugging bit definitions for the various kinds of debug
+    messages that can be enabled within the driver.
+
+  pvrusb2-debugifc.[ch] - This module implements a crude command line
+    oriented debug interface into the driver.  Aside from being part
+    of the process for implementing manual firmware extraction (see
+    the pvrusb2 web site mentioned earlier), probably I'm the only one
+    who has ever used this.  It is mainly a debugging aid.
+
+  pvrusb2-eeprom.[ch] - This is glue logic that resides between this
+    driver the tveeprom.ko module, which is itself implemented
+    elsewhere in V4L.
+
+  pvrusb2-encoder.[ch] - This module implements all protocol needed to
+    interact with the Conexant mpeg2 encoder chip within the pvrusb2
+    device.  It is a crude echo of corresponding logic in ivtv,
+    however the design goals (strict isolation) and physical layer
+    (proxy through USB instead of PCI) are enough different that this
+    implementation had to be completely different.
+
+  pvrusb2-hdw-internal.h - This header defines the core data structure
+    in the driver used to track ALL internal state related to control
+    of the hardware.  Nobody outside of the core hardware-handling
+    modules should have any business using this header.  All external
+    access to the driver should be through one of the high level
+    interfaces (e.g. V4L, sysfs, etc), and in fact even those high
+    level interfaces are restricted to the API defined in
+    pvrusb2-hdw.h and NOT this header.
+
+  pvrusb2-hdw.h - This header defines the full internal API for
+    controlling the hardware.  High level interfaces (e.g. V4L, sysfs)
+    will work through here.
+
+  pvrusb2-hdw.c - This module implements all the various bits of logic
+    that handle overall control of a specific pvrusb2 device.
+    (Policy, instantiation, and arbitration of pvrusb2 devices fall
+    within the jurisdiction of pvrusb-context not here).
+
+  pvrusb2-i2c-chips-*.c - These modules implement the glue logic to
+    tie together and configure various I2C modules as they attach to
+    the I2C bus.  There are two versions of this file.  The "v4l2"
+    version is intended to be used in-tree alongside V4L, where we
+    implement just the logic that makes sense for a pure V4L
+    environment.  The "all" version is intended for use outside of
+    V4L, where we might encounter other possibly "challenging" modules
+    from ivtv or older kernel snapshots (or even the support modules
+    in the standalone snapshot).
+
+  pvrusb2-i2c-cmd-v4l1.[ch] - This module implements generic V4L1
+    compatible commands to the I2C modules.  It is here where state
+    changes inside the pvrusb2 driver are translated into V4L1
+    commands that are in turn send to the various I2C modules.
+
+  pvrusb2-i2c-cmd-v4l2.[ch] - This module implements generic V4L2
+    compatible commands to the I2C modules.  It is here where state
+    changes inside the pvrusb2 driver are translated into V4L2
+    commands that are in turn send to the various I2C modules.
+
+  pvrusb2-i2c-core.[ch] - This module provides an implementation of a
+    kernel-friendly I2C adaptor driver, through which other external
+    I2C client drivers (e.g. msp3400, tuner, lirc) may connect and
+    operate corresponding chips within the the pvrusb2 device.  It is
+    through here that other V4L modules can reach into this driver to
+    operate specific pieces (and those modules are in turn driven by
+    glue logic which is coordinated by pvrusb2-hdw, doled out by
+    pvrusb2-context, and then ultimately made available to users
+    through one of the high level interfaces).
+
+  pvrusb2-io.[ch] - This module implements a very low level ring of
+    transfer buffers, required in order to stream data from the
+    device.  This module is *very* low level.  It only operates the
+    buffers and makes no attempt to define any policy or mechanism for
+    how such buffers might be used.
+
+  pvrusb2-ioread.[ch] - This module layers on top of pvrusb2-io.[ch]
+    to provide a streaming API usable by a read() system call style of
+    I/O.  Right now this is the only layer on top of pvrusb2-io.[ch],
+    however the underlying architecture here was intended to allow for
+    other styles of I/O to be implemented with additonal modules, like
+    mmap()'ed buffers or something even more exotic.
+
+  pvrusb2-main.c - This is the top level of the driver.  Module level
+    and USB core entry points are here.  This is our "main".
+
+  pvrusb2-sysfs.[ch] - This is the high level interface which ties the
+    pvrusb2 driver into sysfs.  Through this interface you can do
+    everything with the driver except actually stream data.
+
+  pvrusb2-tuner.[ch] - This is glue logic that resides between this
+    driver and the tuner.ko I2C client driver (which is found
+    elsewhere in V4L).
+
+  pvrusb2-util.h - This header defines some common macros used
+    throughout the driver.  These macros are not really specific to
+    the driver, but they had to go somewhere.
+
+  pvrusb2-v4l2.[ch] - This is the high level interface which ties the
+    pvrusb2 driver into video4linux.  It is through here that V4L
+    applications can open and operate the driver in the usual V4L
+    ways.  Note that **ALL** V4L functionality is published only
+    through here and nowhere else.
+
+  pvrusb2-video-*.[ch] - This is glue logic that resides between this
+    driver and the saa711x.ko I2C client driver (which is found
+    elsewhere in V4L).  Note that saa711x.ko used to be known as
+    saa7115.ko in ivtv.  There are two versions of this; one is
+    selected depending on the particular saa711[5x].ko that is found.
+
+  pvrusb2.h - This header contains compile time tunable parameters
+    (and at the moment the driver has very little that needs to be
+    tuned).
+
+
+  -Mike Isely
+  isely@pobox.com
+
index 12187a33e31021f519a09bdbd14e311e46f18451..d9ee6336c1d49e6cf262d814251741cd340a1036 100644 (file)
  to run the program with an "&" to run it in the background!)
 
  If you want to write a program to be compatible with the PC Watchdog
- driver, simply do the following:
-
--- Snippet of code --
-/*
- * Watchdog Driver Test Program
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/types.h>
-#include <linux/watchdog.h>
-
-int fd;
-
-/*
- * This function simply sends an IOCTL to the driver, which in turn ticks
- * the PC Watchdog card to reset its internal timer so it doesn't trigger
- * a computer reset.
- */
-void keep_alive(void)
-{
-    int dummy;
-
-    ioctl(fd, WDIOC_KEEPALIVE, &dummy);
-}
-
-/*
- * The main program.  Run the program with "-d" to disable the card,
- * or "-e" to enable the card.
- */
-int main(int argc, char *argv[])
-{
-    fd = open("/dev/watchdog", O_WRONLY);
-
-    if (fd == -1) {
-       fprintf(stderr, "Watchdog device not enabled.\n");
-       fflush(stderr);
-       exit(-1);
-    }
-
-    if (argc > 1) {
-       if (!strncasecmp(argv[1], "-d", 2)) {
-           ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
-           fprintf(stderr, "Watchdog card disabled.\n");
-           fflush(stderr);
-           exit(0);
-       } else if (!strncasecmp(argv[1], "-e", 2)) {
-           ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
-           fprintf(stderr, "Watchdog card enabled.\n");
-           fflush(stderr);
-           exit(0);
-       } else {
-           fprintf(stderr, "-d to disable, -e to enable.\n");
-           fprintf(stderr, "run by itself to tick the card.\n");
-           fflush(stderr);
-           exit(0);
-       }
-    } else {
-       fprintf(stderr, "Watchdog Ticking Away!\n");
-       fflush(stderr);
-    }
-
-    while(1) {
-       keep_alive();
-       sleep(1);
-    }
-}
--- End snippet --
+ driver, simply use of modify the watchdog test program:
+ Documentation/watchdog/src/watchdog-test.c
+
 
  Other IOCTL functions include:
 
diff --git a/Documentation/watchdog/src/watchdog-simple.c b/Documentation/watchdog/src/watchdog-simple.c
new file mode 100644 (file)
index 0000000..85cf17c
--- /dev/null
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <fcntl.h>
+
+int main(int argc, const char *argv[]) {
+       int fd = open("/dev/watchdog", O_WRONLY);
+       if (fd == -1) {
+               perror("watchdog");
+               exit(1);
+       }
+       while (1) {
+               write(fd, "\0", 1);
+               fsync(fd);
+               sleep(10);
+       }
+}
diff --git a/Documentation/watchdog/src/watchdog-test.c b/Documentation/watchdog/src/watchdog-test.c
new file mode 100644 (file)
index 0000000..65f6c19
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Watchdog Driver Test Program
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+
+int fd;
+
+/*
+ * This function simply sends an IOCTL to the driver, which in turn ticks
+ * the PC Watchdog card to reset its internal timer so it doesn't trigger
+ * a computer reset.
+ */
+void keep_alive(void)
+{
+    int dummy;
+
+    ioctl(fd, WDIOC_KEEPALIVE, &dummy);
+}
+
+/*
+ * The main program.  Run the program with "-d" to disable the card,
+ * or "-e" to enable the card.
+ */
+int main(int argc, char *argv[])
+{
+    fd = open("/dev/watchdog", O_WRONLY);
+
+    if (fd == -1) {
+       fprintf(stderr, "Watchdog device not enabled.\n");
+       fflush(stderr);
+       exit(-1);
+    }
+
+    if (argc > 1) {
+       if (!strncasecmp(argv[1], "-d", 2)) {
+           ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
+           fprintf(stderr, "Watchdog card disabled.\n");
+           fflush(stderr);
+           exit(0);
+       } else if (!strncasecmp(argv[1], "-e", 2)) {
+           ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
+           fprintf(stderr, "Watchdog card enabled.\n");
+           fflush(stderr);
+           exit(0);
+       } else {
+           fprintf(stderr, "-d to disable, -e to enable.\n");
+           fprintf(stderr, "run by itself to tick the card.\n");
+           fflush(stderr);
+           exit(0);
+       }
+    } else {
+       fprintf(stderr, "Watchdog Ticking Away!\n");
+       fflush(stderr);
+    }
+
+    while(1) {
+       keep_alive();
+       sleep(1);
+    }
+}
index 21ed5117366240d2a33af5af7f5605733bd514c1..958ff3d48be3dd7288afa5e59b53cde05ccc8487 100644 (file)
@@ -34,22 +34,7 @@ activates as soon as /dev/watchdog is opened and will reboot unless
 the watchdog is pinged within a certain time, this time is called the
 timeout or margin.  The simplest way to ping the watchdog is to write
 some data to the device.  So a very simple watchdog daemon would look
-like this:
-
-#include <stdlib.h>
-#include <fcntl.h>
-
-int main(int argc, const char *argv[]) {
-       int fd=open("/dev/watchdog",O_WRONLY);
-       if (fd==-1) {
-               perror("watchdog");
-               exit(1);
-       }
-       while(1) {
-               write(fd, "\0", 1);
-               sleep(10);
-       }
-}
+like this source file:  see Documentation/watchdog/src/watchdog-simple.c
 
 A more advanced driver could for example check that a HTTP server is
 still responding before doing the write call to ping the watchdog.
@@ -110,7 +95,40 @@ current timeout using the GETTIMEOUT ioctl.
     ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
     printf("The timeout was is %d seconds\n", timeout);
 
-Envinronmental monitoring:
+Pretimeouts:
+
+Some watchdog timers can be set to have a trigger go off before the
+actual time they will reset the system.  This can be done with an NMI,
+interrupt, or other mechanism.  This allows Linux to record useful
+information (like panic information and kernel coredumps) before it
+resets.
+
+    pretimeout = 10;
+    ioctl(fd, WDIOC_SETPRETIMEOUT, &pretimeout);
+
+Note that the pretimeout is the number of seconds before the time
+when the timeout will go off.  It is not the number of seconds until
+the pretimeout.  So, for instance, if you set the timeout to 60 seconds
+and the pretimeout to 10 seconds, the pretimout will go of in 50
+seconds.  Setting a pretimeout to zero disables it.
+
+There is also a get function for getting the pretimeout:
+
+    ioctl(fd, WDIOC_GETPRETIMEOUT, &timeout);
+    printf("The pretimeout was is %d seconds\n", timeout);
+
+Not all watchdog drivers will support a pretimeout.
+
+Get the number of seconds before reboot:
+
+Some watchdog drivers have the ability to report the remaining time
+before the system will reboot. The WDIOC_GETTIMELEFT is the ioctl
+that returns the number of seconds before reboot.
+
+    ioctl(fd, WDIOC_GETTIMELEFT, &timeleft);
+    printf("The timeout was is %d seconds\n", timeleft);
+
+Environmental monitoring:
 
 All watchdog drivers are required return more information about the system,
 some do temperature, fan and power level monitoring, some can tell you
@@ -169,6 +187,10 @@ The watchdog saw a keepalive ping since it was last queried.
 
        WDIOF_SETTIMEOUT        Can set/get the timeout
 
+The watchdog can do pretimeouts.
+
+       WDIOF_PRETIMEOUT        Pretimeout (in seconds), get/set
+
 
 For those drivers that return any bits set in the option field, the
 GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current
index dffda29c8799c1a2c0709a362400487fb5cc6047..4b1ff69cc19a7ea5010cecee914523b67d5dbd3c 100644 (file)
@@ -65,28 +65,7 @@ The external event interfaces on the WDT boards are not currently supported.
 Minor numbers are however allocated for it.
 
 
-Example Watchdog Driver
------------------------
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-int main(int argc, const char *argv[])
-{
-       int fd=open("/dev/watchdog",O_WRONLY);
-       if(fd==-1)
-       {
-               perror("watchdog");
-               exit(1);
-       }
-       while(1)
-       {
-               write(fd,"\0",1);
-               fsync(fd);
-               sleep(10);
-       }
-}
+Example Watchdog Driver:  see Documentation/watchdog/src/watchdog-simple.c
 
 
 Contact Information
index da677f829f7689966bf09aeda6d89fc4b6a876d1..63af36cf7f6e356fc917b1ac86f6e879be5bc0fd 100644 (file)
@@ -49,15 +49,15 @@ select_smp_affinity(unsigned int irq)
        static int last_cpu;
        int cpu = last_cpu + 1;
 
-       if (!irq_desc[irq].handler->set_affinity || irq_user_affinity[irq])
+       if (!irq_desc[irq].chip->set_affinity || irq_user_affinity[irq])
                return 1;
 
        while (!cpu_possible(cpu))
                cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
        last_cpu = cpu;
 
-       irq_affinity[irq] = cpumask_of_cpu(cpu);
-       irq_desc[irq].handler->set_affinity(irq, cpumask_of_cpu(cpu));
+       irq_desc[irq].affinity = cpumask_of_cpu(cpu);
+       irq_desc[irq].chip->set_affinity(irq, cpumask_of_cpu(cpu));
        return 0;
 }
 #endif /* CONFIG_SMP */
@@ -93,7 +93,7 @@ show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[irq]);
 #endif
-               seq_printf(p, " %14s", irq_desc[irq].handler->typename);
+               seq_printf(p, " %14s", irq_desc[irq].chip->typename);
                seq_printf(p, "  %c%s",
                        (action->flags & SA_INTERRUPT)?'+':' ',
                        action->name);
index 9d34ce26e5efc9231eb3581de7b158438818944d..f20f2dff9c438599c6e182eaf9222bf34450b45a 100644 (file)
@@ -233,7 +233,7 @@ void __init
 init_rtc_irq(void)
 {
        irq_desc[RTC_IRQ].status = IRQ_DISABLED;
-       irq_desc[RTC_IRQ].handler = &rtc_irq_type;
+       irq_desc[RTC_IRQ].chip = &rtc_irq_type;
        setup_irq(RTC_IRQ, &timer_irqaction);
 }
 
index b188683b83fd04a4ec8265e4bf1c5c06da8c1694..ac893bd48036cf6cf613d82a042eb6860b690830 100644 (file)
@@ -109,7 +109,7 @@ init_i8259a_irqs(void)
 
        for (i = 0; i < 16; i++) {
                irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].handler = &i8259a_irq_type;
+               irq_desc[i].chip = &i8259a_irq_type;
        }
 
        setup_irq(2, &cascade);
index 146a20b9e3d563208715c5033214e0e16d1d7f8e..3b581415bab0bdaa5e9607cb14faf4dc7debed10 100644 (file)
@@ -120,7 +120,7 @@ init_pyxis_irqs(unsigned long ignore_mask)
                if ((ignore_mask >> i) & 1)
                        continue;
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &pyxis_irq_type;
+               irq_desc[i].chip = &pyxis_irq_type;
        }
 
        setup_irq(16+7, &isa_cascade_irqaction);
index 0a87e466918c2e72fb59e4a5f087a1e5fa268007..8e4d121f84ccf87745aa6149e0a1a26e53649211 100644 (file)
@@ -67,7 +67,7 @@ init_srm_irqs(long max, unsigned long ignore_mask)
                if (i < 64 && ((ignore_mask >> i) & 1))
                        continue;
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &srm_irq_type;
+               irq_desc[i].chip = &srm_irq_type;
        }
 }
 
index 2a8b364c822e9f0e17c9ead5352ab84ad9f1ace6..4ea6711e55aa5263812ba401a84dbae7ff5d4dbf 100644 (file)
@@ -124,12 +124,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final);
 
 void
 pcibios_align_resource(void *data, struct resource *res,
-                      unsigned long size, unsigned long align)
+                      resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
        struct pci_controller *hose = dev->sysdata;
        unsigned long alignto;
-       unsigned long start = res->start;
+       resource_size_t start = res->start;
 
        if (res->flags & IORESOURCE_IO) {
                /* Make sure we start at our min on all hoses */
index 558b83368559396f4d50f793d37d8e7dd83c26d1..254c507a608c076f9e09aa8acb83edfea90d2975 100644 (file)
@@ -481,7 +481,7 @@ register_cpus(void)
                struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
                if (!p)
                        return -ENOMEM;
-               register_cpu(p, i, NULL);
+               register_cpu(p, i);
        }
        return 0;
 }
index d7f0e97fe56fbeed9a93f102116de960de9c40ec..1a1a2c7a3d944190c8699339c5f38086b434ee83 100644 (file)
@@ -144,7 +144,7 @@ alcor_init_irq(void)
                if (i >= 16+20 && i <= 16+30)
                        continue;
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &alcor_irq_type;
+               irq_desc[i].chip = &alcor_irq_type;
        }
        i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq;
 
index 8e3374d34c95bf2782a34ae7ce2ca749c56b8590..8c9e443d93ad6298b312e424ee48db22fd23ebe6 100644 (file)
@@ -124,7 +124,7 @@ common_init_irq(void (*srm_dev_int)(unsigned long v, struct pt_regs *r))
 
                for (i = 16; i < 35; ++i) {
                        irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-                       irq_desc[i].handler = &cabriolet_irq_type;
+                       irq_desc[i].chip = &cabriolet_irq_type;
                }
        }
 
index d5da6b1b28eec6cd557942ff1684f371a9ccc22a..b28c8f1c6e10b078fb0b1173ce64ad538bc23dda 100644 (file)
@@ -300,7 +300,7 @@ init_tsunami_irqs(struct hw_interrupt_type * ops, int imin, int imax)
        long i;
        for (i = imin; i <= imax; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = ops;
+               irq_desc[i].chip = ops;
        }
 }
 
index 61a79c354f0bdece82ed231db04aae15706fc226..aeb8e0277905660275943dd0b0678c3ba08a19b6 100644 (file)
@@ -137,7 +137,7 @@ eb64p_init_irq(void)
 
        for (i = 16; i < 32; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &eb64p_irq_type;
+               irq_desc[i].chip = &eb64p_irq_type;
        }               
 
        common_init_isa_dma();
index bd6e5f0e43c7e443b1d23dd6935df6d26d2e2e61..64a785baf53a0f1ffac8ebfcb904a4ec4c01c0d6 100644 (file)
@@ -154,7 +154,7 @@ eiger_init_irq(void)
 
        for (i = 16; i < 128; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &eiger_irq_type;
+               irq_desc[i].chip = &eiger_irq_type;
        }
 }
 
index fcabb7c96a16588f7367eb554d7b3ad8b9ee3047..0148e095638f8c6d40183ca098f49746f2f5d9f8 100644 (file)
@@ -206,11 +206,11 @@ jensen_init_irq(void)
 {
        init_i8259a_irqs();
 
-       irq_desc[1].handler = &jensen_local_irq_type;
-       irq_desc[4].handler = &jensen_local_irq_type;
-       irq_desc[3].handler = &jensen_local_irq_type;
-       irq_desc[7].handler = &jensen_local_irq_type;
-       irq_desc[9].handler = &jensen_local_irq_type;
+       irq_desc[1].chip = &jensen_local_irq_type;
+       irq_desc[4].chip = &jensen_local_irq_type;
+       irq_desc[3].chip = &jensen_local_irq_type;
+       irq_desc[7].chip = &jensen_local_irq_type;
+       irq_desc[9].chip = &jensen_local_irq_type;
 
        common_init_isa_dma();
 }
index e32fee50522076c7cfaf685d80690e2c0846c135..36d2159543769758904fe8125b7c037b4984efcc 100644 (file)
@@ -303,7 +303,7 @@ init_io7_irqs(struct io7 *io7,
        /* Set up the lsi irqs.  */
        for (i = 0; i < 128; ++i) {
                irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[base + i].handler = lsi_ops;
+               irq_desc[base + i].chip = lsi_ops;
        }
 
        /* Disable the implemented irqs in hardware.  */
@@ -317,7 +317,7 @@ init_io7_irqs(struct io7 *io7,
        /* Set up the msi irqs.  */
        for (i = 128; i < (128 + 512); ++i) {
                irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[base + i].handler = msi_ops;
+               irq_desc[base + i].chip = msi_ops;
        }
 
        for (i = 0; i < 16; ++i)
@@ -335,7 +335,7 @@ marvel_init_irq(void)
        /* Reserve the legacy irqs.  */
        for (i = 0; i < 16; ++i) {
                irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].handler = &marvel_legacy_irq_type;
+               irq_desc[i].chip = &marvel_legacy_irq_type;
        }
 
        /* Init the io7 irqs.  */
index d78a0daa6168e3c3216b82f2f8bc514bd94ded74..b741600e3761a794450d07b278b6ffd2afe2b0ff 100644 (file)
@@ -117,7 +117,7 @@ mikasa_init_irq(void)
 
        for (i = 16; i < 32; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &mikasa_irq_type;
+               irq_desc[i].chip = &mikasa_irq_type;
        }
 
        init_i8259a_irqs();
index 65061f5d741062e01ed1487a7bb389ec770245b2..55db02d318d74172804f5ee67ae1ebd25e046b7d 100644 (file)
@@ -139,7 +139,7 @@ noritake_init_irq(void)
 
        for (i = 16; i < 48; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &noritake_irq_type;
+               irq_desc[i].chip = &noritake_irq_type;
        }
 
        init_i8259a_irqs();
index 05888a02a6049415e53b5ac0c84022eb39d5a605..949607e3d6fbe82395c641b1f94ecb3d99ef1b12 100644 (file)
@@ -180,7 +180,7 @@ rawhide_init_irq(void)
 
        for (i = 16; i < 128; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &rawhide_irq_type;
+               irq_desc[i].chip = &rawhide_irq_type;
        }
 
        init_i8259a_irqs();
index 58404243057b65711300cf786175f62597122f04..6ae50605263592061869345ecfe1856a1c33467e 100644 (file)
@@ -117,7 +117,7 @@ rx164_init_irq(void)
        rx164_update_irq_hw(0);
        for (i = 16; i < 40; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &rx164_irq_type;
+               irq_desc[i].chip = &rx164_irq_type;
        }
 
        init_i8259a_irqs();
index a7ff84474aceebc7603455ec09b8180471d09798..24dea40c9bfe823feea687efcea7677bb42bae12 100644 (file)
@@ -537,7 +537,7 @@ sable_lynx_init_irq(int nr_irqs)
 
        for (i = 0; i < nr_irqs; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &sable_lynx_irq_type;
+               irq_desc[i].chip = &sable_lynx_irq_type;
        }
 
        common_init_isa_dma();
index 7955bdfc2db0e2fabd4b44da9eed48ecc947ead2..2c75cd1fd81aab537e6b93615011baba52b98e2c 100644 (file)
@@ -154,7 +154,7 @@ takara_init_irq(void)
 
        for (i = 16; i < 128; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = &takara_irq_type;
+               irq_desc[i].chip = &takara_irq_type;
        }
 
        common_init_isa_dma();
index 2551fb49ae099150561407adc726e410b8e03c9f..13f3ed8ed7ac2f1c166d6d9392a0785bccbb71fd 100644 (file)
@@ -189,7 +189,7 @@ init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax)
        long i;
        for (i = imin; i <= imax; ++i) {
                irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i].handler = ops;
+               irq_desc[i].chip = ops;
        }
 }
 
index 1553f470246e6b74eecb0ba9630982d3a0cf5c97..22c5798fe083ba03cf16e88ec6fe4088fce61ce3 100644 (file)
@@ -199,14 +199,14 @@ wildfire_init_irq_per_pca(int qbbno, int pcano)
                if (i == 2)
                        continue;
                irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i+irq_bias].handler = &wildfire_irq_type;
+               irq_desc[i+irq_bias].chip = &wildfire_irq_type;
        }
 
        irq_desc[36+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
-       irq_desc[36+irq_bias].handler = &wildfire_irq_type;
+       irq_desc[36+irq_bias].chip = &wildfire_irq_type;
        for (i = 40; i < 64; ++i) {
                irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
-               irq_desc[i+irq_bias].handler = &wildfire_irq_type;
+               irq_desc[i+irq_bias].chip = &wildfire_irq_type;
        }
 
        setup_irq(32+irq_bias, &isa_enable);    
index 3d1a3fb7d5fc17901b200f9a4e8a8097d271f066..f123c7c9fc989d507a5c834b2208fc94a5f02c54 100644 (file)
@@ -188,23 +188,27 @@ config ARCH_IMX
 
 config ARCH_IOP3XX
        bool "IOP3xx-based"
+       depends on MMU
        select PCI
        help
          Support for Intel's IOP3XX (XScale) family of processors.
 
 config ARCH_IXP4XX
        bool "IXP4xx-based"
+       depends on MMU
        help
          Support for Intel's IXP4XX (XScale) family of processors.
 
 config ARCH_IXP2000
        bool "IXP2400/2800-based"
+       depends on MMU
        select PCI
        help
          Support for Intel's IXP2400/2800 (XScale) family of processors.
 
 config ARCH_IXP23XX
        bool "IXP23XX-based"
+       depends on MMU
        select PCI
        help
          Support for Intel's IXP23xx (XScale) family of processors.
@@ -229,6 +233,7 @@ config ARCH_PNX4008
 
 config ARCH_PXA
        bool "PXA2xx-based"
+       depends on MMU
        select ARCH_MTD_XIP
        help
          Support for Intel's PXA2XX processor line.
@@ -339,6 +344,10 @@ config XSCALE_PMU
        depends on CPU_XSCALE && !XSCALE_PMU_TIMER
        default y
 
+if !MMU
+source "arch/arm/Kconfig-nommu"
+endif
+
 endmenu
 
 source "arch/arm/common/Kconfig"
index a601b8b55f3594ba1a0989956c5db5ae9da389fa..7cffbaef064ba60afcec20ca02638ebf70b89a9a 100644 (file)
@@ -22,6 +22,9 @@ obj-$(CONFIG_PCI)             += bios32.o
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_OABI_COMPAT)      += sys_oabi-compat.o
 
+obj-$(CONFIG_CRUNCH)           += crunch.o crunch-bits.o
+AFLAGS_crunch-bits.o           := -Wa,-mcpu=ep9312
+
 obj-$(CONFIG_IWMMXT)           += iwmmxt.o
 AFLAGS_iwmmxt.o                        := -Wa,-mcpu=iwmmxt
 
index c49b5d4d7fca2a77217c15732c0fbeeefdf90f6f..da69e660574bf1510f8f1457d07c7368b7de12e2 100644 (file)
@@ -109,11 +109,13 @@ EXPORT_SYMBOL(memchr);
 EXPORT_SYMBOL(__memzero);
 
        /* user mem (segment) */
-EXPORT_SYMBOL(__arch_copy_from_user);
-EXPORT_SYMBOL(__arch_copy_to_user);
-EXPORT_SYMBOL(__arch_clear_user);
-EXPORT_SYMBOL(__arch_strnlen_user);
-EXPORT_SYMBOL(__arch_strncpy_from_user);
+EXPORT_SYMBOL(__strnlen_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+
+#ifdef CONFIG_MMU
+EXPORT_SYMBOL(__copy_from_user);
+EXPORT_SYMBOL(__copy_to_user);
+EXPORT_SYMBOL(__clear_user);
 
 EXPORT_SYMBOL(__get_user_1);
 EXPORT_SYMBOL(__get_user_2);
@@ -123,6 +125,7 @@ EXPORT_SYMBOL(__put_user_1);
 EXPORT_SYMBOL(__put_user_2);
 EXPORT_SYMBOL(__put_user_4);
 EXPORT_SYMBOL(__put_user_8);
+#endif
 
        /* crypto hash */
 EXPORT_SYMBOL(sha_transform);
index 396efba9bacd2d6fb6351e18149576cc1d779665..447ede5143a8f7bf16f3b0ea48d0ebd500d5a3ca 100644 (file)
@@ -59,6 +59,9 @@ int main(void)
   DEFINE(TI_VFPSTATE,          offsetof(struct thread_info, vfpstate));
 #ifdef CONFIG_IWMMXT
   DEFINE(TI_IWMMXT_STATE,      offsetof(struct thread_info, fpstate.iwmmxt));
+#endif
+#ifdef CONFIG_CRUNCH
+  DEFINE(TI_CRUNCH_STATE,      offsetof(struct thread_info, crunchstate));
 #endif
   BLANK();
   DEFINE(S_R0,                 offsetof(struct pt_regs, ARM_r0));
index 302fc140154797e8d2d59045a40a940cad69092a..45da06fc1ba1a1481f66e102e0fc582aaa2096f5 100644 (file)
@@ -304,7 +304,7 @@ static inline int pdev_bad_for_parity(struct pci_dev *dev)
 static void __devinit
 pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev)
 {
-       unsigned long offset;
+       resource_size_t offset;
        int i;
 
        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
@@ -634,9 +634,9 @@ char * __init pcibios_setup(char *str)
  * which might be mirrored at 0x0100-0x03ff..
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
-       unsigned long start = res->start;
+       resource_size_t start = res->start;
 
        if (res->flags & IORESOURCE_IO && start & 0x300)
                start = (start + 0x3ff) & ~0x3ff;
diff --git a/arch/arm/kernel/crunch-bits.S b/arch/arm/kernel/crunch-bits.S
new file mode 100644 (file)
index 0000000..a268867
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * arch/arm/kernel/crunch-bits.S
+ * Cirrus MaverickCrunch context switching and handling
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * Shamelessly stolen from the iWMMXt code by Nicolas Pitre, which is
+ * Copyright (c) 2003-2004, MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/arch/ep93xx-regs.h>
+
+/*
+ * We can't use hex constants here due to a bug in gas.
+ */
+#define CRUNCH_MVDX0           0
+#define CRUNCH_MVDX1           8
+#define CRUNCH_MVDX2           16
+#define CRUNCH_MVDX3           24
+#define CRUNCH_MVDX4           32
+#define CRUNCH_MVDX5           40
+#define CRUNCH_MVDX6           48
+#define CRUNCH_MVDX7           56
+#define CRUNCH_MVDX8           64
+#define CRUNCH_MVDX9           72
+#define CRUNCH_MVDX10          80
+#define CRUNCH_MVDX11          88
+#define CRUNCH_MVDX12          96
+#define CRUNCH_MVDX13          104
+#define CRUNCH_MVDX14          112
+#define CRUNCH_MVDX15          120
+#define CRUNCH_MVAX0L          128
+#define CRUNCH_MVAX0M          132
+#define CRUNCH_MVAX0H          136
+#define CRUNCH_MVAX1L          140
+#define CRUNCH_MVAX1M          144
+#define CRUNCH_MVAX1H          148
+#define CRUNCH_MVAX2L          152
+#define CRUNCH_MVAX2M          156
+#define CRUNCH_MVAX2H          160
+#define CRUNCH_MVAX3L          164
+#define CRUNCH_MVAX3M          168
+#define CRUNCH_MVAX3H          172
+#define CRUNCH_DSPSC           176
+
+#define CRUNCH_SIZE            184
+
+       .text
+
+/*
+ * Lazy switching of crunch coprocessor context
+ *
+ * r10 = struct thread_info pointer
+ * r9  = ret_from_exception
+ * lr  = undefined instr exit
+ *
+ * called from prefetch exception handler with interrupts disabled
+ */
+ENTRY(crunch_task_enable)
+       ldr     r8, =(EP93XX_APB_VIRT_BASE + 0x00130000)        @ syscon addr
+
+       ldr     r1, [r8, #0x80]
+       tst     r1, #0x00800000                 @ access to crunch enabled?
+       movne   pc, lr                          @ if so no business here
+       mov     r3, #0xaa                       @ unlock syscon swlock
+       str     r3, [r8, #0xc0]
+       orr     r1, r1, #0x00800000             @ enable access to crunch
+       str     r1, [r8, #0x80]
+
+       ldr     r3, =crunch_owner
+       add     r0, r10, #TI_CRUNCH_STATE       @ get task crunch save area
+       ldr     r2, [sp, #60]                   @ current task pc value
+       ldr     r1, [r3]                        @ get current crunch owner
+       str     r0, [r3]                        @ this task now owns crunch
+       sub     r2, r2, #4                      @ adjust pc back
+       str     r2, [sp, #60]
+
+       ldr     r2, [r8, #0x80]
+       mov     r2, r2                          @ flush out enable (@@@)
+
+       teq     r1, #0                          @ test for last ownership
+       mov     lr, r9                          @ normal exit from exception
+       beq     crunch_load                     @ no owner, skip save
+
+crunch_save:
+       cfstr64         mvdx0, [r1, #CRUNCH_MVDX0]      @ save 64b registers
+       cfstr64         mvdx1, [r1, #CRUNCH_MVDX1]
+       cfstr64         mvdx2, [r1, #CRUNCH_MVDX2]
+       cfstr64         mvdx3, [r1, #CRUNCH_MVDX3]
+       cfstr64         mvdx4, [r1, #CRUNCH_MVDX4]
+       cfstr64         mvdx5, [r1, #CRUNCH_MVDX5]
+       cfstr64         mvdx6, [r1, #CRUNCH_MVDX6]
+       cfstr64         mvdx7, [r1, #CRUNCH_MVDX7]
+       cfstr64         mvdx8, [r1, #CRUNCH_MVDX8]
+       cfstr64         mvdx9, [r1, #CRUNCH_MVDX9]
+       cfstr64         mvdx10, [r1, #CRUNCH_MVDX10]
+       cfstr64         mvdx11, [r1, #CRUNCH_MVDX11]
+       cfstr64         mvdx12, [r1, #CRUNCH_MVDX12]
+       cfstr64         mvdx13, [r1, #CRUNCH_MVDX13]
+       cfstr64         mvdx14, [r1, #CRUNCH_MVDX14]
+       cfstr64         mvdx15, [r1, #CRUNCH_MVDX15]
+
+#ifdef __ARMEB__
+#error fix me for ARMEB
+#endif
+
+       cfmv32al        mvfx0, mvax0                    @ save 72b accumulators
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0L]
+       cfmv32am        mvfx0, mvax0
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0M]
+       cfmv32ah        mvfx0, mvax0
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0H]
+       cfmv32al        mvfx0, mvax1
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1L]
+       cfmv32am        mvfx0, mvax1
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1M]
+       cfmv32ah        mvfx0, mvax1
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1H]
+       cfmv32al        mvfx0, mvax2
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2L]
+       cfmv32am        mvfx0, mvax2
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2M]
+       cfmv32ah        mvfx0, mvax2
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2H]
+       cfmv32al        mvfx0, mvax3
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3L]
+       cfmv32am        mvfx0, mvax3
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3M]
+       cfmv32ah        mvfx0, mvax3
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3H]
+
+       cfmv32sc        mvdx0, dspsc                    @ save status word
+       cfstr64         mvdx0, [r1, #CRUNCH_DSPSC]
+
+       teq             r0, #0                          @ anything to load?
+       cfldr64eq       mvdx0, [r1, #CRUNCH_MVDX0]      @ mvdx0 was clobbered
+       moveq           pc, lr
+
+crunch_load:
+       cfldr64         mvdx0, [r0, #CRUNCH_DSPSC]      @ load status word
+       cfmvsc32        dspsc, mvdx0
+
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0L]     @ load 72b accumulators
+       cfmval32        mvax0, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0M]
+       cfmvam32        mvax0, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0H]
+       cfmvah32        mvax0, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1L]
+       cfmval32        mvax1, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1M]
+       cfmvam32        mvax1, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1H]
+       cfmvah32        mvax1, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2L]
+       cfmval32        mvax2, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2M]
+       cfmvam32        mvax2, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2H]
+       cfmvah32        mvax2, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3L]
+       cfmval32        mvax3, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3M]
+       cfmvam32        mvax3, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3H]
+       cfmvah32        mvax3, mvfx0
+
+       cfldr64         mvdx0, [r0, #CRUNCH_MVDX0]      @ load 64b registers
+       cfldr64         mvdx1, [r0, #CRUNCH_MVDX1]
+       cfldr64         mvdx2, [r0, #CRUNCH_MVDX2]
+       cfldr64         mvdx3, [r0, #CRUNCH_MVDX3]
+       cfldr64         mvdx4, [r0, #CRUNCH_MVDX4]
+       cfldr64         mvdx5, [r0, #CRUNCH_MVDX5]
+       cfldr64         mvdx6, [r0, #CRUNCH_MVDX6]
+       cfldr64         mvdx7, [r0, #CRUNCH_MVDX7]
+       cfldr64         mvdx8, [r0, #CRUNCH_MVDX8]
+       cfldr64         mvdx9, [r0, #CRUNCH_MVDX9]
+       cfldr64         mvdx10, [r0, #CRUNCH_MVDX10]
+       cfldr64         mvdx11, [r0, #CRUNCH_MVDX11]
+       cfldr64         mvdx12, [r0, #CRUNCH_MVDX12]
+       cfldr64         mvdx13, [r0, #CRUNCH_MVDX13]
+       cfldr64         mvdx14, [r0, #CRUNCH_MVDX14]
+       cfldr64         mvdx15, [r0, #CRUNCH_MVDX15]
+
+       mov     pc, lr
+
+/*
+ * Back up crunch regs to save area and disable access to them
+ * (mainly for gdb or sleep mode usage)
+ *
+ * r0 = struct thread_info pointer of target task or NULL for any
+ */
+ENTRY(crunch_task_disable)
+       stmfd   sp!, {r4, r5, lr}
+
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r4, =(EP93XX_APB_VIRT_BASE + 0x00130000)        @ syscon addr
+
+       ldr     r3, =crunch_owner
+       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
+       ldr     r1, [r3]                        @ get current crunch owner
+       teq     r1, #0                          @ any current owner?
+       beq     1f                              @ no: quit
+       teq     r0, #0                          @ any owner?
+       teqne   r1, r2                          @ or specified one?
+       bne     1f                              @ no: quit
+
+       ldr     r5, [r4, #0x80]                 @ enable access to crunch
+       mov     r2, #0xaa
+       str     r2, [r4, #0xc0]
+       orr     r5, r5, #0x00800000
+       str     r5, [r4, #0x80]
+
+       mov     r0, #0                          @ nothing to load
+       str     r0, [r3]                        @ no more current owner
+       ldr     r2, [r4, #0x80]                 @ flush out enable (@@@)
+       mov     r2, r2
+       bl      crunch_save
+
+       mov     r2, #0xaa                       @ disable access to crunch
+       str     r2, [r4, #0xc0]
+       bic     r5, r5, #0x00800000
+       str     r5, [r4, #0x80]
+       ldr     r5, [r4, #0x80]                 @ flush out enable (@@@)
+       mov     r5, r5
+
+1:     msr     cpsr_c, ip                      @ restore interrupt mode
+       ldmfd   sp!, {r4, r5, pc}
+
+/*
+ * Copy crunch state to given memory address
+ *
+ * r0 = struct thread_info pointer of target task
+ * r1 = memory address where to store crunch state
+ *
+ * this is called mainly in the creation of signal stack frames
+ */
+ENTRY(crunch_task_copy)
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r3, =crunch_owner
+       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
+       ldr     r3, [r3]                        @ get current crunch owner
+       teq     r2, r3                          @ does this task own it...
+       beq     1f
+
+       @ current crunch values are in the task save area
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     r0, r1
+       mov     r1, r2
+       mov     r2, #CRUNCH_SIZE
+       b       memcpy
+
+1:     @ this task owns crunch regs -- grab a copy from there
+       mov     r0, #0                          @ nothing to load
+       mov     r3, lr                          @ preserve return address
+       bl      crunch_save
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     pc, r3
+
+/*
+ * Restore crunch state from given memory address
+ *
+ * r0 = struct thread_info pointer of target task
+ * r1 = memory address where to get crunch state from
+ *
+ * this is used to restore crunch state when unwinding a signal stack frame
+ */
+ENTRY(crunch_task_restore)
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r3, =crunch_owner
+       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
+       ldr     r3, [r3]                        @ get current crunch owner
+       teq     r2, r3                          @ does this task own it...
+       beq     1f
+
+       @ this task doesn't own crunch regs -- use its save area
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     r0, r2
+       mov     r2, #CRUNCH_SIZE
+       b       memcpy
+
+1:     @ this task owns crunch regs -- load them directly
+       mov     r0, r1
+       mov     r1, #0                          @ nothing to save
+       mov     r3, lr                          @ preserve return address
+       bl      crunch_load
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     pc, r3
diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
new file mode 100644 (file)
index 0000000..7481759
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * arch/arm/kernel/crunch.c
+ * Cirrus MaverickCrunch context switching and handling
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <asm/arch/ep93xx-regs.h>
+#include <asm/thread_notify.h>
+#include <asm/io.h>
+
+struct crunch_state *crunch_owner;
+
+void crunch_task_release(struct thread_info *thread)
+{
+       local_irq_disable();
+       if (crunch_owner == &thread->crunchstate)
+               crunch_owner = NULL;
+       local_irq_enable();
+}
+
+static int crunch_enabled(u32 devcfg)
+{
+       return !!(devcfg & EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE);
+}
+
+static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
+{
+       struct thread_info *thread = (struct thread_info *)t;
+       struct crunch_state *crunch_state;
+       u32 devcfg;
+
+       crunch_state = &thread->crunchstate;
+
+       switch (cmd) {
+       case THREAD_NOTIFY_FLUSH:
+               memset(crunch_state, 0, sizeof(*crunch_state));
+
+               /*
+                * FALLTHROUGH: Ensure we don't try to overwrite our newly
+                * initialised state information on the first fault.
+                */
+
+       case THREAD_NOTIFY_RELEASE:
+               crunch_task_release(thread);
+               break;
+
+       case THREAD_NOTIFY_SWITCH:
+               devcfg = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
+               if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
+                       devcfg ^= EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
+                       __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
+                       __raw_writel(devcfg, EP93XX_SYSCON_DEVICE_CONFIG);
+               }
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block crunch_notifier_block = {
+       .notifier_call  = crunch_do,
+};
+
+static int __init crunch_init(void)
+{
+       thread_register_notifier(&crunch_notifier_block);
+
+       return 0;
+}
+
+late_initcall(crunch_init);
index 86c92523a346704e7d94c7c1bc9660e5bc383aa6..6423a38839b8b4e86f6105399e209e00ce8f607c 100644 (file)
@@ -492,9 +492,15 @@ call_fpe:
        b       do_fpe                          @ CP#1 (FPE)
        b       do_fpe                          @ CP#2 (FPE)
        mov     pc, lr                          @ CP#3
+#ifdef CONFIG_CRUNCH
+       b       crunch_task_enable              @ CP#4 (MaverickCrunch)
+       b       crunch_task_enable              @ CP#5 (MaverickCrunch)
+       b       crunch_task_enable              @ CP#6 (MaverickCrunch)
+#else
        mov     pc, lr                          @ CP#4
        mov     pc, lr                          @ CP#5
        mov     pc, lr                          @ CP#6
+#endif
        mov     pc, lr                          @ CP#7
        mov     pc, lr                          @ CP#8
        mov     pc, lr                          @ CP#9
index a1d1b2906e8d60006090cdd62012c38f41352221..c40bdc770054c19b8a79e1f660211ec790b39274 100644 (file)
@@ -634,6 +634,32 @@ static int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp)
 
 #endif
 
+#ifdef CONFIG_CRUNCH
+/*
+ * Get the child Crunch state.
+ */
+static int ptrace_getcrunchregs(struct task_struct *tsk, void __user *ufp)
+{
+       struct thread_info *thread = task_thread_info(tsk);
+
+       crunch_task_disable(thread);  /* force it to ram */
+       return copy_to_user(ufp, &thread->crunchstate, CRUNCH_SIZE)
+               ? -EFAULT : 0;
+}
+
+/*
+ * Set the child Crunch state.
+ */
+static int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp)
+{
+       struct thread_info *thread = task_thread_info(tsk);
+
+       crunch_task_release(thread);  /* force a reload */
+       return copy_from_user(&thread->crunchstate, ufp, CRUNCH_SIZE)
+               ? -EFAULT : 0;
+}
+#endif
+
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
        unsigned long tmp;
@@ -765,6 +791,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        child->ptrace_message = data;
                        break;
 
+#ifdef CONFIG_CRUNCH
+               case PTRACE_GETCRUNCHREGS:
+                       ret = ptrace_getcrunchregs(child, (void __user *)data);
+                       break;
+
+               case PTRACE_SETCRUNCHREGS:
+                       ret = ptrace_setcrunchregs(child, (void __user *)data);
+                       break;
+#endif
+
                default:
                        ret = ptrace_request(child, request, addr, data);
                        break;
index 9fc9af88c60c72e54cad5e835c579b95027624e6..6bdf70def01f0c22390aeeba31db56cbd05be7e8 100644 (file)
@@ -119,9 +119,24 @@ DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
  * Standard memory resources
  */
 static struct resource mem_res[] = {
-       { "Video RAM",   0,     0,     IORESOURCE_MEM                   },
-       { "Kernel text", 0,     0,     IORESOURCE_MEM                   },
-       { "Kernel data", 0,     0,     IORESOURCE_MEM                   }
+       {
+               .name = "Video RAM",
+               .start = 0,
+               .end = 0,
+               .flags = IORESOURCE_MEM
+       },
+       {
+               .name = "Kernel text",
+               .start = 0,
+               .end = 0,
+               .flags = IORESOURCE_MEM
+       },
+       {
+               .name = "Kernel data",
+               .start = 0,
+               .end = 0,
+               .flags = IORESOURCE_MEM
+       }
 };
 
 #define video_ram   mem_res[0]
@@ -129,9 +144,24 @@ static struct resource mem_res[] = {
 #define kernel_data mem_res[2]
 
 static struct resource io_res[] = {
-       { "reserved",    0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY },
-       { "reserved",    0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY },
-       { "reserved",    0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY }
+       {
+               .name = "reserved",
+               .start = 0x3bc,
+               .end = 0x3be,
+               .flags = IORESOURCE_IO | IORESOURCE_BUSY
+       },
+       {
+               .name = "reserved",
+               .start = 0x378,
+               .end = 0x37f,
+               .flags = IORESOURCE_IO | IORESOURCE_BUSY
+       },
+       {
+               .name = "reserved",
+               .start = 0x278,
+               .end = 0x27f,
+               .flags = IORESOURCE_IO | IORESOURCE_BUSY
+       }
 };
 
 #define lp0 io_res[0]
@@ -808,7 +838,7 @@ static int __init topology_init(void)
        int cpu;
 
        for_each_possible_cpu(cpu)
-               register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu, NULL);
+               register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu);
 
        return 0;
 }
index 1ce05ec086c6b40366a2d7aa349eef14af1b0410..83a8d3c95eb3ff458631412a96bf5ed6e4f1c742 100644 (file)
@@ -132,6 +132,37 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
        return ret;
 }
 
+#ifdef CONFIG_CRUNCH
+static int preserve_crunch_context(struct crunch_sigframe *frame)
+{
+       char kbuf[sizeof(*frame) + 8];
+       struct crunch_sigframe *kframe;
+
+       /* the crunch context must be 64 bit aligned */
+       kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7);
+       kframe->magic = CRUNCH_MAGIC;
+       kframe->size = CRUNCH_STORAGE_SIZE;
+       crunch_task_copy(current_thread_info(), &kframe->storage);
+       return __copy_to_user(frame, kframe, sizeof(*frame));
+}
+
+static int restore_crunch_context(struct crunch_sigframe *frame)
+{
+       char kbuf[sizeof(*frame) + 8];
+       struct crunch_sigframe *kframe;
+
+       /* the crunch context must be 64 bit aligned */
+       kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7);
+       if (__copy_from_user(kframe, frame, sizeof(*frame)))
+               return -1;
+       if (kframe->magic != CRUNCH_MAGIC ||
+           kframe->size != CRUNCH_STORAGE_SIZE)
+               return -1;
+       crunch_task_restore(current_thread_info(), &kframe->storage);
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_IWMMXT
 
 static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
@@ -214,6 +245,10 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
        err |= !valid_user_regs(regs);
 
        aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
+#ifdef CONFIG_CRUNCH
+       if (err == 0)
+               err |= restore_crunch_context(&aux->crunch);
+#endif
 #ifdef CONFIG_IWMMXT
        if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
                err |= restore_iwmmxt_context(&aux->iwmmxt);
@@ -333,6 +368,10 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
        err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
 
        aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
+#ifdef CONFIG_CRUNCH
+       if (err == 0)
+               err |= preserve_crunch_context(&aux->crunch);
+#endif
 #ifdef CONFIG_IWMMXT
        if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
                err |= preserve_iwmmxt_context(&aux->iwmmxt);
index 2b254e88595c76e15c233290e0f1339f04e5a621..2df9688a70282fca86ac0fb854a64da305961111 100644 (file)
@@ -80,6 +80,10 @@ SECTIONS
                *(.exit.text)
                *(.exit.data)
                *(.exitcall.exit)
+#ifndef CONFIG_MMU
+               *(.fixup)
+               *(__ex_table)
+#endif
        }
 
        .text : {                       /* Real text segment            */
@@ -87,7 +91,9 @@ SECTIONS
                        *(.text)
                        SCHED_TEXT
                        LOCK_TEXT
+#ifdef CONFIG_MMU
                        *(.fixup)
+#endif
                        *(.gnu.warning)
                        *(.rodata)
                        *(.rodata.*)
@@ -142,7 +148,9 @@ SECTIONS
                 */
                . = ALIGN(32);
                __start___ex_table = .;
+#ifdef CONFIG_MMU
                *(__ex_table)
+#endif
                __stop___ex_table = .;
 
                /*
index 7b726b627ea5ee38d85090774ab5d7f555d0c84c..30351cd4560dfcc7052a8be4eaa84620643878a3 100644 (file)
@@ -6,28 +6,31 @@
 
 lib-y          := backtrace.o changebit.o csumipv6.o csumpartial.o   \
                   csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
-                  copy_page.o delay.o findbit.o memchr.o memcpy.o    \
+                  delay.o findbit.o memchr.o memcpy.o                \
                   memmove.o memset.o memzero.o setbit.o              \
                   strncpy_from_user.o strnlen_user.o                 \
                   strchr.o strrchr.o                                 \
                   testchangebit.o testclearbit.o testsetbit.o        \
-                  getuser.o putuser.o clear_user.o                   \
                   ashldi3.o ashrdi3.o lshrdi3.o muldi3.o             \
                   ucmpdi2.o lib1funcs.o div64.o sha1.o               \
                   io-readsb.o io-writesb.o io-readsl.o io-writesl.o
 
+mmu-y  := clear_user.o copy_page.o getuser.o putuser.o
+
 # the code in uaccess.S is not preemption safe and
 # probably faster on ARMv3 only
 ifeq ($(CONFIG_PREEMPT),y)
-  lib-y        += copy_from_user.o copy_to_user.o
+  mmu-y        += copy_from_user.o copy_to_user.o
 else
 ifneq ($(CONFIG_CPU_32v3),y)
-  lib-y        += copy_from_user.o copy_to_user.o
+  mmu-y        += copy_from_user.o copy_to_user.o
 else
-  lib-y        += uaccess.o
+  mmu-y        += uaccess.o
 endif
 endif
 
+lib-$(CONFIG_MMU) += $(mmu-y)
+
 ifeq ($(CONFIG_CPU_32v3),y)
   lib-y        += io-readsw-armv3.o io-writesw-armv3.o
 else
index 058b80d72aa1371a748b52cbee5b61c8653392b8..91f993f2e9dbdfd5786733dcaaec3e36ae26cf31 100644 (file)
@@ -97,16 +97,13 @@ ENTRY(c_backtrace)
                b       1007f
 
 /*
- * Fixup for LDMDB
+ * Fixup for LDMDB.  Note that this must not be in the fixup section.
  */
-               .section .fixup,"ax"
-               .align  0
 1007:          ldr     r0, =.Lbad
                mov     r1, frame
                bl      printk
                ldmfd   sp!, {r4 - r8, pc}
                .ltorg
-               .previous
                
                .section __ex_table,"a"
                .align  3
index ea435ae2e4a55738536413f48ce3b85f675576ba..ecb28dcdaf7b00704533a9241d64e3d65b9bde49 100644 (file)
 
                .text
 
-/* Prototype: int __arch_clear_user(void *addr, size_t sz)
+/* Prototype: int __clear_user(void *addr, size_t sz)
  * Purpose  : clear some user memory
  * Params   : addr - user memory address to clear
  *          : sz   - number of bytes to clear
  * Returns  : number of bytes NOT cleared
  */
-ENTRY(__arch_clear_user)
+ENTRY(__clear_user)
                stmfd   sp!, {r1, lr}
                mov     r2, #0
                cmp     r1, #4
index 7497393a0e814d588a07c3f4bcd9fe4d65b3a62f..6b7363ce749cd80a451315e3ba8b7e94e53f9eee 100644 (file)
@@ -16,7 +16,7 @@
 /*
  * Prototype:
  *
- *     size_t __arch_copy_from_user(void *to, const void *from, size_t n)
+ *     size_t __copy_from_user(void *to, const void *from, size_t n)
  *
  * Purpose:
  *
@@ -83,7 +83,7 @@
 
        .text
 
-ENTRY(__arch_copy_from_user)
+ENTRY(__copy_from_user)
 
 #include "copy_template.S"
 
index 4a6d8ea14022329444eb03535f0dd12058ccf89d..5224d94688d907caca22efec0794a9daee2a2211 100644 (file)
@@ -16,7 +16,7 @@
 /*
  * Prototype:
  *
- *     size_t __arch_copy_to_user(void *to, const void *from, size_t n)
+ *     size_t __copy_to_user(void *to, const void *from, size_t n)
  *
  * Purpose:
  *
@@ -86,7 +86,7 @@
 
        .text
 
-ENTRY(__arch_copy_to_user)
+ENTRY(__copy_to_user)
 
 #include "copy_template.S"
 
index 35649f04fcac3f6c2c0b53327a7399c3de46d7f0..36e3741a37729a59f8eb30e5d66ba3ab5e67fcbc 100644 (file)
@@ -20,7 +20,7 @@
  * returns the number of characters copied (strlen of copied string),
  *  -EFAULT on exception, or "len" if we fill the whole buffer
  */
-ENTRY(__arch_strncpy_from_user)
+ENTRY(__strncpy_from_user)
        mov     ip, r1
 1:     subs    r2, r2, #1
 USER(  ldrplbt r3, [r1], #1)
index 3668a15991efddda846e01e01aed9127c98b895b..18d8fa4f925a92c397006d7105d9fa8b7bc8c4d0 100644 (file)
        .text
        .align  5
 
-/* Prototype: unsigned long __arch_strnlen_user(const char *str, long n)
+/* Prototype: unsigned long __strnlen_user(const char *str, long n)
  * Purpose  : get length of a string in user memory
  * Params   : str - address of string in user memory
  * Returns  : length of string *including terminator*
  *           or zero on exception, or n + 1 if too long
  */
-ENTRY(__arch_strnlen_user)
+ENTRY(__strnlen_user)
        mov     r2, r0
 1:
 USER(  ldrbt   r3, [r0], #1)
index 1f1545d737be8b29ef3bccb9be3f752525f50f75..b48bd6d5fd83144ca4705becef558faadb33f725 100644 (file)
@@ -19,7 +19,7 @@
 
 #define PAGE_SHIFT 12
 
-/* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n)
+/* Prototype: int __copy_to_user(void *to, const char *from, size_t n)
  * Purpose  : copy a block to user memory from kernel memory
  * Params   : to   - user memory
  *          : from - kernel memory
@@ -39,7 +39,7 @@ USER(         strgtbt r3, [r0], #1)                   @ May fault
                sub     r2, r2, ip
                b       .Lc2u_dest_aligned
 
-ENTRY(__arch_copy_to_user)
+ENTRY(__copy_to_user)
                stmfd   sp!, {r2, r4 - r7, lr}
                cmp     r2, #4
                blt     .Lc2u_not_enough
@@ -283,7 +283,7 @@ USER(               strgtbt r3, [r0], #1)                   @ May fault
 9001:          ldmfd   sp!, {r0, r4 - r7, pc}
                .previous
 
-/* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n);
+/* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
  * Purpose  : copy a block from user memory to kernel memory
  * Params   : to   - kernel memory
  *          : from - user memory
@@ -302,7 +302,7 @@ USER(               ldrgtbt r3, [r1], #1)                   @ May fault
                sub     r2, r2, ip
                b       .Lcfu_dest_aligned
 
-ENTRY(__arch_copy_from_user)
+ENTRY(__copy_from_user)
                stmfd   sp!, {r0, r2, r4 - r7, lr}
                cmp     r2, #4
                blt     .Lcfu_not_enough
index cec5a21ca4e341593e5a6b4470a7cc903c111f70..e15e4c54a2538a53b50c238766d2ba3ac6598e44 100644 (file)
@@ -2,8 +2,19 @@ if ARCH_EP93XX
 
 menu "Cirrus EP93xx Implementation Options"
 
+config CRUNCH
+       bool "Support for MaverickCrunch"
+       help
+         Enable kernel support for MaverickCrunch.
+
 comment "EP93xx Platforms"
 
+config MACH_EDB9315
+       bool "Support Cirrus Logic EDB9315"
+       help
+         Say 'Y' here if you want your kernel to support the Cirrus
+         Logic EDB9315 Evaluation Board.
+
 config MACH_GESBC9312
        bool "Support Glomation GESBC-9312-sx"
        help
index 05a48a21038eadea89feffd7d33ab78f13544067..dfa7e2e8a18b65621d87eeab94c689d1990c14f2 100644 (file)
@@ -6,5 +6,6 @@ obj-m                   :=
 obj-n                  :=
 obj-                   :=
 
+obj-$(CONFIG_MACH_EDB9315)     += edb9315.o
 obj-$(CONFIG_MACH_GESBC9312)   += gesbc9312.o
 obj-$(CONFIG_MACH_TS72XX)      += ts72xx.o
diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c
new file mode 100644 (file)
index 0000000..ef7482f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * arch/arm/mach-ep93xx/edb9315.c
+ * Cirrus Logic EDB9315 support.
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.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>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static struct physmap_flash_data edb9315_flash_data = {
+       .width          = 4,
+};
+
+static struct resource edb9315_flash_resource = {
+       .start          = 0x60000000,
+       .end            = 0x61ffffff,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device edb9315_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &edb9315_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &edb9315_flash_resource,
+};
+
+static void __init edb9315_init_machine(void)
+{
+       ep93xx_init_devices();
+       platform_device_register(&edb9315_flash);
+}
+
+MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
+       /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb9315_init_machine,
+MACHINE_END
index 47cc6c8b7c79a1ca3e4ade460044149bbd212907..2c28d66d260ec7d1a7660278d3a77e99630ff51f 100644 (file)
@@ -30,7 +30,7 @@ static struct physmap_flash_data gesbc9312_flash_data = {
 
 static struct resource gesbc9312_flash_resource = {
        .start          = 0x60000000,
-       .end            = 0x60800000,
+       .end            = 0x607fffff,
        .flags          = IORESOURCE_MEM,
 };
 
index 6e5a56cd5ae872a9a7b69cb1d4c69debf28c73a9..0b3b875b1875221dd0695abd3150f4eacd401097 100644 (file)
@@ -118,7 +118,7 @@ static struct physmap_flash_data ts72xx_flash_data = {
 
 static struct resource ts72xx_flash_resource = {
        .start          = TS72XX_NOR_PHYS_BASE,
-       .end            = TS72XX_NOR_PHYS_BASE + 0x01000000,
+       .end            = TS72XX_NOR_PHYS_BASE + 0x00ffffff,
        .flags          = IORESOURCE_MEM,
 };
 
index dc5e489c70bc1144f60b13be9c90f214f2ea2b1f..357351fbb1e217fba6d6b833194b48a499cf3e4e 100644 (file)
@@ -59,7 +59,7 @@ static struct physmap_flash_data espresso_flash_data = {
 
 static struct resource espresso_flash_resource = {
        .start          = 0x90000000,
-       .end            = 0x92000000,
+       .end            = 0x91ffffff,
        .flags          = IORESOURCE_MEM,
 };
 
index 535b334ee045296b0df665f269a8a88ace6f7ef8..e0886871cc773d34effab66e4ca9e5be199b43cb 100644 (file)
@@ -304,7 +304,7 @@ static struct physmap_flash_data ixdp2351_flash_data = {
 
 static struct resource ixdp2351_flash_resource = {
        .start          = 0x90000000,
-       .end            = 0x94000000,
+       .end            = 0x93ffffff,
        .flags          = IORESOURCE_MEM,
 };
 
index b9f5d13fcfe126422528cf1502ed0a9f697bad01..92ad18f4125167f45e562922771c81fba3c7a168 100644 (file)
@@ -143,7 +143,7 @@ static struct physmap_flash_data roadrunner_flash_data = {
 
 static struct resource roadrunner_flash_resource = {
        .start          = 0x90000000,
-       .end            = 0x94000000,
+       .end            = 0x93ffffff,
        .flags          = IORESOURCE_MEM,
 };
 
index 539b596005fc266b2c49f8d0edfa22d7758b1b13..d9635ff4b10cb97bd979e7f8022dd346e929ae5e 100644 (file)
@@ -88,8 +88,8 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
 
        if (type == IRQT_PROBE) {
            /* Don't mess with enabled GPIOs using preconfigured edges or
-              GPIOs set to alternate function during probe */
-               if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
+              GPIOs set to alternate function or to output during probe */
+               if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx] | GPDR(gpio)) &
                    GPIO_bit(gpio))
                        return 0;
                if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
index 838bc525e83698c912c188104164d3fb6e48bbf1..9a2258270de9cb1e7e9d12b9b45b90f9092d3582 100644 (file)
@@ -69,6 +69,7 @@ void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
 
        s3c_device_i2c.name  = "s3c2440-i2c";
        s3c_device_nand.name = "s3c2440-nand";
+       s3c_device_usbgadget.name = "s3c2440-usbgadget";
 }
 
 void __init s3c244x_init_clocks(int xtal)
index ecf5e232a6fc2a3e0d6c419ca918933bdacd2fd3..c4bca753165bd2eec732ebe9515cbdc3fba1715a 100644 (file)
@@ -15,8 +15,8 @@ config CPU_ARM610
        select CPU_32v3
        select CPU_CACHE_V3
        select CPU_CACHE_VIVT
-       select CPU_COPY_V3
-       select CPU_TLB_V3
+       select CPU_COPY_V3 if MMU
+       select CPU_TLB_V3 if MMU
        help
          The ARM610 is the successor to the ARM3 processor
          and was produced by VLSI Technology Inc.
@@ -31,8 +31,8 @@ config CPU_ARM710
        select CPU_32v3
        select CPU_CACHE_V3
        select CPU_CACHE_VIVT
-       select CPU_COPY_V3
-       select CPU_TLB_V3
+       select CPU_COPY_V3 if MMU
+       select CPU_TLB_V3 if MMU
        help
          A 32-bit RISC microprocessor based on the ARM7 processor core
          designed by Advanced RISC Machines Ltd. The ARM710 is the
@@ -50,8 +50,8 @@ config CPU_ARM720T
        select CPU_ABRT_LV4T
        select CPU_CACHE_V4
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WT
-       select CPU_TLB_V4WT
+       select CPU_COPY_V4WT if MMU
+       select CPU_TLB_V4WT if MMU
        help
          A 32-bit RISC processor with 8kByte Cache, Write Buffer and
          MMU built around an ARM7TDMI core.
@@ -68,8 +68,8 @@ config CPU_ARM920T
        select CPU_ABRT_EV4T
        select CPU_CACHE_V4WT
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM920T is licensed to be produced by numerous vendors,
          and is used in the Maverick EP9312 and the Samsung S3C2410.
@@ -89,8 +89,8 @@ config CPU_ARM922T
        select CPU_ABRT_EV4T
        select CPU_CACHE_V4WT
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM922T is a version of the ARM920T, but with smaller
          instruction and data caches. It is used in Altera's
@@ -108,8 +108,8 @@ config CPU_ARM925T
        select CPU_ABRT_EV4T
        select CPU_CACHE_V4WT
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM925T is a mix between the ARM920T and ARM926T, but with
          different instruction and data caches. It is used in TI's OMAP
@@ -126,8 +126,8 @@ config CPU_ARM926T
        select CPU_32v5
        select CPU_ABRT_EV5TJ
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        help
          This is a variant of the ARM920.  It has slightly different
          instruction sequences for cache and TLB operations.  Curiously,
@@ -144,8 +144,8 @@ config CPU_ARM1020
        select CPU_ABRT_EV4T
        select CPU_CACHE_V4WT
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM1020 is the 32K cached version of the ARM10 processor,
          with an addition of a floating-point unit.
@@ -161,8 +161,8 @@ config CPU_ARM1020E
        select CPU_ABRT_EV4T
        select CPU_CACHE_V4WT
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WBI if MMU
        depends on n
 
 # ARM1022E
@@ -172,8 +172,8 @@ config CPU_ARM1022
        select CPU_32v5
        select CPU_ABRT_EV4T
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB # can probably do better
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU # can probably do better
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM1022E is an implementation of the ARMv5TE architecture
          based upon the ARM10 integer core with a 16KiB L1 Harvard cache,
@@ -189,8 +189,8 @@ config CPU_ARM1026
        select CPU_32v5
        select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB # can probably do better
-       select CPU_TLB_V4WBI
+       select CPU_COPY_V4WB if MMU # can probably do better
+       select CPU_TLB_V4WBI if MMU
        help
          The ARM1026EJ-S is an implementation of the ARMv5TEJ architecture
          based upon the ARM10 integer core.
@@ -207,8 +207,8 @@ config CPU_SA110
        select CPU_ABRT_EV4
        select CPU_CACHE_V4WB
        select CPU_CACHE_VIVT
-       select CPU_COPY_V4WB
-       select CPU_TLB_V4WB
+       select CPU_COPY_V4WB if MMU
+       select CPU_TLB_V4WB if MMU
        help
          The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and
          is available at five speeds ranging from 100 MHz to 233 MHz.
@@ -227,7 +227,7 @@ config CPU_SA1100
        select CPU_ABRT_EV4
        select CPU_CACHE_V4WB
        select CPU_CACHE_VIVT
-       select CPU_TLB_V4WB
+       select CPU_TLB_V4WB if MMU
 
 # XScale
 config CPU_XSCALE
@@ -237,7 +237,7 @@ config CPU_XSCALE
        select CPU_32v5
        select CPU_ABRT_EV5T
        select CPU_CACHE_VIVT
-       select CPU_TLB_V4WBI
+       select CPU_TLB_V4WBI if MMU
 
 # XScale Core Version 3
 config CPU_XSC3
@@ -247,7 +247,7 @@ config CPU_XSC3
        select CPU_32v5
        select CPU_ABRT_EV5T
        select CPU_CACHE_VIVT
-       select CPU_TLB_V4WBI
+       select CPU_TLB_V4WBI if MMU
        select IO_36
 
 # ARMv6
@@ -258,8 +258,8 @@ config CPU_V6
        select CPU_ABRT_EV6
        select CPU_CACHE_V6
        select CPU_CACHE_VIPT
-       select CPU_COPY_V6
-       select CPU_TLB_V6
+       select CPU_COPY_V6 if MMU
+       select CPU_TLB_V6 if MMU
 
 # ARMv6k
 config CPU_32v6K
@@ -277,17 +277,17 @@ config CPU_32v6K
 # This defines the compiler instruction set which depends on the machine type.
 config CPU_32v3
        bool
-       select TLS_REG_EMUL if SMP
+       select TLS_REG_EMUL if SMP || !MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
 
 config CPU_32v4
        bool
-       select TLS_REG_EMUL if SMP
+       select TLS_REG_EMUL if SMP || !MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
 
 config CPU_32v5
        bool
-       select TLS_REG_EMUL if SMP
+       select TLS_REG_EMUL if SMP || !MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
 
 config CPU_32v6
@@ -334,6 +334,7 @@ config CPU_CACHE_VIVT
 config CPU_CACHE_VIPT
        bool
 
+if MMU
 # The copy-page model
 config CPU_COPY_V3
        bool
@@ -372,6 +373,8 @@ config CPU_TLB_V4WBI
 config CPU_TLB_V6
        bool
 
+endif
+
 #
 # CPU supports 36-bit I/O
 #
index 07a538505784068f949759f12e2dbec2253a1dd8..21a2770226ee418e9756d2a6663a255850352333 100644 (file)
@@ -2,10 +2,16 @@
 # Makefile for the linux arm-specific parts of the memory manager.
 #
 
-obj-y                          := consistent.o extable.o fault-armv.o \
-                                  fault.o flush.o init.o ioremap.o mmap.o \
+obj-y                          := consistent.o extable.o fault.o init.o \
+                                  iomap.o
+
+obj-$(CONFIG_MMU)              += fault-armv.o flush.o ioremap.o mmap.o \
                                   mm-armv.o
 
+ifneq ($(CONFIG_MMU),y)
+obj-y                          += nommu.o
+endif
+
 obj-$(CONFIG_MODULES)          += proc-syms.o
 
 obj-$(CONFIG_ALIGNMENT_TRAP)   += alignment.o
index 9ea1f87a7079b863ee4d061103ef46b2aa00fa9b..989fd681c822de5be93e6d66fe1676423e87b6a6 100644 (file)
@@ -26,8 +26,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#define TABLE_SIZE     (2 * PTRS_PER_PTE * sizeof(pte_t))
-
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff --git a/arch/arm/mm/iomap.c b/arch/arm/mm/iomap.c
new file mode 100644 (file)
index 0000000..62066f3
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *  linux/arch/arm/mm/iomap.c
+ *
+ * Map IO port and PCI memory spaces so that {read,write}[bwl] can
+ * be used to access this memory.
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+
+#ifdef __io
+void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+       return __io(port);
+}
+EXPORT_SYMBOL(ioport_map);
+
+void ioport_unmap(void __iomem *addr)
+{
+}
+EXPORT_SYMBOL(ioport_unmap);
+#endif
+
+#ifdef CONFIG_PCI
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+       unsigned long start = pci_resource_start(dev, bar);
+       unsigned long len   = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (!len || !start)
+               return NULL;
+       if (maxlen && len > maxlen)
+               len = maxlen;
+       if (flags & IORESOURCE_IO)
+               return ioport_map(start, len);
+       if (flags & IORESOURCE_MEM) {
+               if (flags & IORESOURCE_CACHEABLE)
+                       return ioremap(start, len);
+               return ioremap_nocache(start, len);
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(pci_iomap);
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+       if ((unsigned long)addr >= VMALLOC_START &&
+           (unsigned long)addr < VMALLOC_END)
+               iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
+#endif
index c1f7180c7beda07ff35d3211880902b8a83c2a2c..7691cfdba56778d7f97768b66c243e66eb735dc2 100644 (file)
@@ -176,50 +176,3 @@ void __iounmap(void __iomem *addr)
        vunmap((void *)(PAGE_MASK & (unsigned long)addr));
 }
 EXPORT_SYMBOL(__iounmap);
-
-#ifdef __io
-void __iomem *ioport_map(unsigned long port, unsigned int nr)
-{
-       return __io(port);
-}
-EXPORT_SYMBOL(ioport_map);
-
-void ioport_unmap(void __iomem *addr)
-{
-}
-EXPORT_SYMBOL(ioport_unmap);
-#endif
-
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#include <linux/ioport.h>
-
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       unsigned long start = pci_resource_start(dev, bar);
-       unsigned long len   = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len || !start)
-               return NULL;
-       if (maxlen && len > maxlen)
-               len = maxlen;
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM) {
-               if (flags & IORESOURCE_CACHEABLE)
-                       return ioremap(start, len);
-               return ioremap_nocache(start, len);
-       }
-       return NULL;
-}
-EXPORT_SYMBOL(pci_iomap);
-
-void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
-{
-       if ((unsigned long)addr >= VMALLOC_START &&
-           (unsigned long)addr < VMALLOC_END)
-               iounmap(addr);
-}
-EXPORT_SYMBOL(pci_iounmap);
-#endif
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
new file mode 100644 (file)
index 0000000..1464ed8
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  linux/arch/arm/mm/nommu.c
+ *
+ * ARM uCLinux supporting functions.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/page.h>
+
+void flush_dcache_page(struct page *page)
+{
+       __cpuc_flush_dcache_page(page_address(page));
+}
+EXPORT_SYMBOL(flush_dcache_page);
+
+void __iomem *__ioremap_pfn(unsigned long pfn, unsigned long offset,
+                           size_t size, unsigned long flags)
+{
+       if (pfn >= (0x100000000ULL >> PAGE_SHIFT))
+               return NULL;
+       return (void __iomem *) (offset + (pfn << PAGE_SHIFT));
+}
+EXPORT_SYMBOL(__ioremap_pfn);
+
+void __iomem *__ioremap(unsigned long phys_addr, size_t size,
+                       unsigned long flags)
+{
+       return (void __iomem *)phys_addr;
+}
+EXPORT_SYMBOL(__ioremap);
+
+void __iounmap(void __iomem *addr)
+{
+}
+EXPORT_SYMBOL(__iounmap);
index 959588884fa5ea38afe966938120370dff0ce05f..b9abbafca81225c5c6295438d49147c89b5f7860 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -101,7 +102,9 @@ ENTRY(cpu_arm1020_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -359,6 +362,7 @@ ENTRY(cpu_arm1020_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm1020_switch_mm)
+#ifdef CONFIG_MMU
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mcr     p15, 0, r3, c7, c10, 4
        mov     r1, #0xF                        @ 16 segments
@@ -383,6 +387,7 @@ ENTRY(cpu_arm1020_switch_mm)
        mcr     p15, 0, r1, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, r1, c8, c7, 0           @ invalidate I & D TLBs
+#endif /* CONFIG_MMU */
        mov     pc, lr
         
 /*
@@ -392,6 +397,7 @@ ENTRY(cpu_arm1020_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm1020_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -421,6 +427,7 @@ ENTRY(cpu_arm1020_set_pte)
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -430,7 +437,9 @@ __arm1020_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, arm1020_cr1_clear
        bic     r0, r0, r5
index be6d081ff2b71219d672e28b141c9cb93e32edb8..bcd5ee022e00ae36bde2c50362fdd81114ee3107 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -101,7 +102,9 @@ ENTRY(cpu_arm1020e_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -344,6 +347,7 @@ ENTRY(cpu_arm1020e_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm1020e_switch_mm)
+#ifdef CONFIG_MMU
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mcr     p15, 0, r3, c7, c10, 4
        mov     r1, #0xF                        @ 16 segments
@@ -367,6 +371,7 @@ ENTRY(cpu_arm1020e_switch_mm)
        mcr     p15, 0, r1, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, r1, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
         
 /*
@@ -376,6 +381,7 @@ ENTRY(cpu_arm1020e_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm1020e_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -403,6 +409,7 @@ ENTRY(cpu_arm1020e_set_pte)
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -412,7 +419,9 @@ __arm1020e_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, arm1020e_cr1_clear
        bic     r0, r0, r5
index f778545d57a2d9825805417a8677cb8a41c5eed2..b0ccff4fadd2559912e5edf50483369726f7fd3a 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -90,7 +91,9 @@ ENTRY(cpu_arm1022_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -333,6 +336,7 @@ ENTRY(cpu_arm1022_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm1022_switch_mm)
+#ifdef CONFIG_MMU
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mov     r1, #(CACHE_DSEGMENTS - 1) << 5 @ 16 segments
 1:     orr     r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
@@ -349,6 +353,7 @@ ENTRY(cpu_arm1022_switch_mm)
        mcr     p15, 0, r1, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, r1, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
         
 /*
@@ -358,6 +363,7 @@ ENTRY(cpu_arm1022_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm1022_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -385,6 +391,7 @@ ENTRY(cpu_arm1022_set_pte)
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -394,7 +401,9 @@ __arm1022_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, arm1022_cr1_clear
        bic     r0, r0, r5
index 148c111fde732b4b41b83bfe513949a0647cf77a..abe850c9a641ef0ef6074eaaabeb8484852a2929 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -90,7 +91,9 @@ ENTRY(cpu_arm1026_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -327,6 +330,7 @@ ENTRY(cpu_arm1026_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm1026_switch_mm)
+#ifdef CONFIG_MMU
        mov     r1, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
 1:     mrc     p15, 0, r15, c7, c14, 3         @ test, clean, invalidate
@@ -338,6 +342,7 @@ ENTRY(cpu_arm1026_switch_mm)
        mcr     p15, 0, r1, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, r1, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
         
 /*
@@ -347,6 +352,7 @@ ENTRY(cpu_arm1026_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm1026_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -374,6 +380,7 @@ ENTRY(cpu_arm1026_set_pte)
 #ifndef CONFIG_CPU_DCACHE_DISABLE
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
 
@@ -384,8 +391,10 @@ __arm1026_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
        mcr     p15, 0, r4, c2, c0              @ load page table pointer
+#endif
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mov     r0, #4                          @ explicitly disable writeback
        mcr     p15, 7, r0, c15, c0, 0
index 540359b475d07d0a293467c870911885adab9e6a..7a705edfa4b22461e68106dca194c7d831d5eb70 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mm/proc-arm6,7.S
  *
  *  Copyright (C) 1997-2000 Russell King
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * 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
@@ -199,10 +200,12 @@ ENTRY(cpu_arm7_do_idle)
  */
 ENTRY(cpu_arm6_switch_mm)
 ENTRY(cpu_arm7_switch_mm)
+#ifdef CONFIG_MMU
                mov     r1, #0
                mcr     p15, 0, r1, c7, c0, 0           @ flush cache
                mcr     p15, 0, r0, c2, c0, 0           @ update page table ptr
                mcr     p15, 0, r1, c5, c0, 0           @ flush TLBs
+#endif
                mov     pc, lr
 
 /*
@@ -214,6 +217,7 @@ ENTRY(cpu_arm7_switch_mm)
                .align  5
 ENTRY(cpu_arm6_set_pte)
 ENTRY(cpu_arm7_set_pte)
+#ifdef CONFIG_MMU
                str     r1, [r0], #-2048                @ linux version
 
                eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -232,6 +236,7 @@ ENTRY(cpu_arm7_set_pte)
                movne   r2, #0
 
                str     r2, [r0]                        @ hardware version
+#endif /* CONFIG_MMU */
                mov     pc, lr
 
 /*
@@ -243,7 +248,9 @@ ENTRY(cpu_arm6_reset)
 ENTRY(cpu_arm7_reset)
                mov     r1, #0
                mcr     p15, 0, r1, c7, c0, 0           @ flush cache
+#ifdef CONFIG_MMU
                mcr     p15, 0, r1, c5, c0, 0           @ flush TLB
+#endif
                mov     r1, #0x30
                mcr     p15, 0, r1, c1, c0, 0           @ turn off MMU etc
                mov     pc, r0
@@ -253,19 +260,27 @@ ENTRY(cpu_arm7_reset)
                .type   __arm6_setup, #function
 __arm6_setup:  mov     r0, #0
                mcr     p15, 0, r0, c7, c0              @ flush caches on v3
+#ifdef CONFIG_MMU
                mcr     p15, 0, r0, c5, c0              @ flush TLBs on v3
                mov     r0, #0x3d                       @ . ..RS BLDP WCAM
                orr     r0, r0, #0x100                  @ . ..01 0011 1101
+#else
+               mov     r0, #0x3c                       @ . ..RS BLDP WCA.
+#endif
                mov     pc, lr
                .size   __arm6_setup, . - __arm6_setup
 
                .type   __arm7_setup, #function
 __arm7_setup:  mov     r0, #0
                mcr     p15, 0, r0, c7, c0              @ flush caches on v3
+#ifdef CONFIG_MMU
                mcr     p15, 0, r0, c5, c0              @ flush TLBs on v3
                mcr     p15, 0, r0, c3, c0              @ load domain access register
                mov     r0, #0x7d                       @ . ..RS BLDP WCAM
                orr     r0, r0, #0x100                  @ . ..01 0111 1101
+#else
+               mov     r0, #0x7c                       @ . ..RS BLDP WCA.
+#endif
                mov     pc, lr
                .size   __arm7_setup, . - __arm7_setup
 
index 26f00ee2ad9a308f79e4f00a75b177535d20a480..86102467d37f98fedf2ff9e75a83f2e3430dd795 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
  *                     Rob Scott (rscott@mtrob.fdns.net)
  *  Copyright (C) 2000 ARM Limited, Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 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
@@ -29,6 +30,7 @@
  *                     out of 'proc-arm6,7.S' per RMK discussion
  *   07-25-2000 SJH    Added idle function.
  *   08-25-2000        DBS     Updated for integration of ARM Ltd version.
+ *   04-20-2004 HSC    modified for non-paged memory management mode.
  */
 #include <linux/linkage.h>
 #include <linux/init.h>
@@ -75,10 +77,12 @@ ENTRY(cpu_arm720_do_idle)
  *          the new.
  */
 ENTRY(cpu_arm720_switch_mm)
+#ifdef CONFIG_MMU
                mov     r1, #0
                mcr     p15, 0, r1, c7, c7, 0           @ invalidate cache
                mcr     p15, 0, r0, c2, c0, 0           @ update page table ptr
                mcr     p15, 0, r1, c8, c7, 0           @ flush TLB (v4)
+#endif
                mov     pc, lr
 
 /*
@@ -89,6 +93,7 @@ ENTRY(cpu_arm720_switch_mm)
  */
                .align  5
 ENTRY(cpu_arm720_set_pte)
+#ifdef CONFIG_MMU
                str     r1, [r0], #-2048                @ linux version
 
                eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -107,6 +112,7 @@ ENTRY(cpu_arm720_set_pte)
                movne   r2, #0
 
                str     r2, [r0]                        @ hardware version
+#endif
                mov     pc, lr
 
 /*
@@ -117,7 +123,9 @@ ENTRY(cpu_arm720_set_pte)
 ENTRY(cpu_arm720_reset)
                mov     ip, #0
                mcr     p15, 0, ip, c7, c7, 0           @ invalidate cache
+#ifdef CONFIG_MMU
                mcr     p15, 0, ip, c8, c7, 0           @ flush TLB (v4)
+#endif
                mrc     p15, 0, ip, c1, c0, 0           @ get ctrl register
                bic     ip, ip, #0x000f                 @ ............wcam
                bic     ip, ip, #0x2100                 @ ..v....s........
@@ -130,7 +138,9 @@ ENTRY(cpu_arm720_reset)
 __arm710_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7, 0           @ invalidate caches
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7, 0           @ flush TLB (v4)
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register
        ldr     r5, arm710_cr1_clear
        bic     r0, r0, r5
@@ -156,7 +166,9 @@ arm710_cr1_set:
 __arm720_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7, 0           @ invalidate caches
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7, 0           @ flush TLB (v4)
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register
        ldr     r5, arm720_cr1_clear
        bic     r0, r0, r5
index a17f79e0199c9ea0160ff2a987267e18fc26dd0b..31dc839ba07c9557ff0dae53de0827b345e870cd 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1999,2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -97,7 +98,9 @@ ENTRY(cpu_arm920_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -317,6 +320,7 @@ ENTRY(cpu_arm920_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm920_switch_mm)
+#ifdef CONFIG_MMU
        mov     ip, #0
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
@@ -337,6 +341,7 @@ ENTRY(cpu_arm920_switch_mm)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
 
 /*
@@ -346,6 +351,7 @@ ENTRY(cpu_arm920_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm920_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -372,6 +378,7 @@ ENTRY(cpu_arm920_set_pte)
        mov     r0, r0
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -381,7 +388,9 @@ __arm920_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, arm920_cr1_clear
        bic     r0, r0, r5
index bbde4a024a4848ca73014a7ddb01844f6481111c..9e57c34f5c098532c044aa2b1f1c02faa6aa3610 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 1999,2000 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
  *  Copyright (C) 2001 Altera Corporation
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -99,7 +100,9 @@ ENTRY(cpu_arm922_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -321,6 +324,7 @@ ENTRY(cpu_arm922_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm922_switch_mm)
+#ifdef CONFIG_MMU
        mov     ip, #0
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
@@ -341,6 +345,7 @@ ENTRY(cpu_arm922_switch_mm)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
 
 /*
@@ -350,6 +355,7 @@ ENTRY(cpu_arm922_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm922_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -376,6 +382,7 @@ ENTRY(cpu_arm922_set_pte)
        mov     r0, r0
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -385,7 +392,9 @@ __arm922_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, arm922_cr1_clear
        bic     r0, r0, r5
index 224ce226a01bc24f5c561dd7b0680c5970803d34..8d47c9f3f931b1aaa1381d5ad15347899fddfeb7 100644 (file)
@@ -9,6 +9,8 @@
  *  Update for Linux-2.6 and cache flush improvements
  *  Copyright (C) 2004 Nokia Corporation by Tony Lindgren <tony@atomide.com>
  *
+ *  hacked for non-paged-MM by Hyok S. Choi, 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
@@ -122,7 +124,9 @@ ENTRY(cpu_arm925_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -369,6 +373,7 @@ ENTRY(cpu_arm925_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm925_switch_mm)
+#ifdef CONFIG_MMU
        mov     ip, #0
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
@@ -383,6 +388,7 @@ ENTRY(cpu_arm925_switch_mm)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
 
 /*
@@ -392,6 +398,7 @@ ENTRY(cpu_arm925_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm925_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -420,6 +427,7 @@ ENTRY(cpu_arm925_set_pte)
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif /* CONFIG_MMU */
        mov     pc, lr
 
        __INIT
@@ -438,7 +446,9 @@ __arm925_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
 
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mov     r0, #4                          @ disable write-back on caches explicitly
index 4e2a087cf3889599225483bb353b29931bdc4886..cb4d8f33d2a3ff4b02146e2475ab8e22e9affbf8 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1999-2001 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -85,7 +86,9 @@ ENTRY(cpu_arm926_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -329,6 +332,7 @@ ENTRY(cpu_arm926_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_arm926_switch_mm)
+#ifdef CONFIG_MMU
        mov     ip, #0
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
        mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
@@ -341,6 +345,7 @@ ENTRY(cpu_arm926_switch_mm)
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mov     pc, lr
 
 /*
@@ -350,6 +355,7 @@ ENTRY(cpu_arm926_switch_mm)
  */
        .align  5
 ENTRY(cpu_arm926_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -378,6 +384,7 @@ ENTRY(cpu_arm926_set_pte)
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
 #endif
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif
        mov     pc, lr
 
        __INIT
@@ -387,7 +394,9 @@ __arm926_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
 
 
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
index a2dd5ae1077dda0c5257a768a6d69c880c0781af..5a760a2c629c11681d072e2d547e791ab1ebb7f1 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mm/proc-sa110.S
  *
  *  Copyright (C) 1997-2002 Russell King
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * 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
@@ -67,7 +68,9 @@ ENTRY(cpu_sa110_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -130,11 +133,15 @@ ENTRY(cpu_sa110_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_sa110_switch_mm)
+#ifdef CONFIG_MMU
        str     lr, [sp, #-4]!
        bl      v4wb_flush_kern_cache_all       @ clears IP
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
        ldr     pc, [sp], #4
+#else
+       mov     pc, lr
+#endif
 
 /*
  * cpu_sa110_set_pte(ptep, pte)
@@ -143,6 +150,7 @@ ENTRY(cpu_sa110_switch_mm)
  */
        .align  5
 ENTRY(cpu_sa110_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -164,6 +172,7 @@ ENTRY(cpu_sa110_set_pte)
        mov     r0, r0
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif
        mov     pc, lr
 
        __INIT
@@ -173,7 +182,9 @@ __sa110_setup:
        mov     r10, #0
        mcr     p15, 0, r10, c7, c7             @ invalidate I,D caches on v4
        mcr     p15, 0, r10, c7, c10, 4         @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r10, c8, c7             @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, sa110_cr1_clear
        bic     r0, r0, r5
index 777ad99c14395584690dfc32cd3c297540edca16..0a2107ad4c32f8750b52cf9424e3c69bb34f685f 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mm/proc-sa1100.S
  *
  *  Copyright (C) 1997-2002 Russell King
+ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
  *
  * 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
@@ -77,7 +78,9 @@ ENTRY(cpu_sa1100_reset)
        mov     ip, #0
        mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
        mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
        mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
        bic     ip, ip, #0x000f                 @ ............wcam
        bic     ip, ip, #0x1100                 @ ...i...s........
@@ -142,12 +145,16 @@ ENTRY(cpu_sa1100_dcache_clean_area)
  */
        .align  5
 ENTRY(cpu_sa1100_switch_mm)
+#ifdef CONFIG_MMU
        str     lr, [sp, #-4]!
        bl      v4wb_flush_kern_cache_all       @ clears IP
        mcr     p15, 0, ip, c9, c0, 0           @ invalidate RB
        mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
        mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
        ldr     pc, [sp], #4
+#else
+       mov     pc, lr
+#endif
 
 /*
  * cpu_sa1100_set_pte(ptep, pte)
@@ -156,6 +163,7 @@ ENTRY(cpu_sa1100_switch_mm)
  */
        .align  5
 ENTRY(cpu_sa1100_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@@ -177,6 +185,7 @@ ENTRY(cpu_sa1100_set_pte)
        mov     r0, r0
        mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif
        mov     pc, lr
 
        __INIT
@@ -186,7 +195,9 @@ __sa1100_setup:
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
        mrc     p15, 0, r0, c1, c0              @ get control register v4
        ldr     r5, sa1100_cr1_clear
        bic     r0, r0, r5
index 09b1a41a6de887f0afd3ebf8e9dbf520b51018c4..ca13d4d05f6551e13fae4d9148fa7c7664e3da08 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mm/proc-v6.S
  *
  *  Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *  Modified by Catalin Marinas for noMMU support
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -88,6 +89,7 @@ ENTRY(cpu_v6_dcache_clean_area)
  *     - we are not using split page tables
  */
 ENTRY(cpu_v6_switch_mm)
+#ifdef CONFIG_MMU
        mov     r2, #0
        ldr     r1, [r1, #MM_CONTEXT_ID]        @ get mm->context.id
 #ifdef CONFIG_SMP
@@ -97,6 +99,7 @@ ENTRY(cpu_v6_switch_mm)
        mcr     p15, 0, r2, c7, c10, 4          @ drain write buffer
        mcr     p15, 0, r0, c2, c0, 0           @ set TTB 0
        mcr     p15, 0, r1, c13, c0, 1          @ set context ID
+#endif
        mov     pc, lr
 
 /*
@@ -119,6 +122,7 @@ ENTRY(cpu_v6_switch_mm)
  *       1111   0   1   1      r/w     r/w
  */
 ENTRY(cpu_v6_set_pte)
+#ifdef CONFIG_MMU
        str     r1, [r0], #-2048                @ linux version
 
        bic     r2, r1, #0x000003f0
@@ -145,6 +149,7 @@ ENTRY(cpu_v6_set_pte)
 
        str     r2, [r0]
        mcr     p15, 0, r0, c7, c10, 1 @ flush_pte
+#endif
        mov     pc, lr
 
 
@@ -194,12 +199,14 @@ __v6_setup:
        mcr     p15, 0, r0, c7, c5, 0           @ invalidate I cache
        mcr     p15, 0, r0, c7, c15, 0          @ clean+invalidate cache
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
+#ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7, 0           @ invalidate I + D TLBs
        mcr     p15, 0, r0, c2, c0, 2           @ TTB control register
 #ifdef CONFIG_SMP
        orr     r4, r4, #TTB_RGN_WBWA|TTB_S     @ mark PTWs shared, outer cacheable
 #endif
        mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
+#endif /* CONFIG_MMU */
 #ifdef CONFIG_VFP
        mrc     p15, 0, r0, c1, c0, 2
        orr     r0, r0, #(0xf << 20)
index 856b665020e770d8a464e40a74cd91a7f5649b7e..6a1238a29d6c4d98d46156a1863e4a342478d7db 100644 (file)
@@ -28,6 +28,10 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config IRQ_PER_CPU
+       bool
+       default y
+
 config CRIS
        bool
        default y
index f3a85b77c17e1c5b68596cf47d6e77587bfaa1bd..dde813e16294ddedf7b1a25264a3f2001c0c8834 100644 (file)
@@ -541,7 +541,7 @@ init_dummy_console(void)
        dummy_driver.init_termios = tty_std_termios;
        dummy_driver.init_termios.c_cflag =
                B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
-       dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 
        dummy_driver.open = dummy_open;
        dummy_driver.close = dummy_close;
index 4b368a122015288dc1b04b9248f19ca8eefbb106..2d5be93b5197c202d37d41d0a4d6334fa0a271a0 100644 (file)
@@ -172,7 +172,7 @@ init_IRQ(void)
 
        /* Initialize IRQ handler descriptiors. */
        for(i = 2; i < NR_IRQS; i++) {
-               irq_desc[i].handler = &crisv10_irq_type;
+               irq_desc[i].chip = &crisv10_irq_type;
                set_int_vector(i, interrupt[i]);
        }
 
index 1e9d062103aec24a993c8c0e4263e4e9778df9a3..a2b9c60c2777e6cf39b94b0789fccf15307ced19 100644 (file)
@@ -43,10 +43,10 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 
 void
 pcibios_align_resource(void *data, struct resource *res,
-                      unsigned long size, unsigned long align)
+                      resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
index ffc1ebf2dfee30b4a3b4ceb039236e4fea58d079..3dc587e6201aee865c762fa71a1807f5dffcd3d3 100644 (file)
@@ -353,7 +353,7 @@ init_dummy_console(void)
        dummy_driver.init_termios = tty_std_termios;
        dummy_driver.init_termios.c_cflag =
                B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
-       dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 
        dummy_driver.open = dummy_open;
        dummy_driver.close = dummy_close;
index c78cc2685133727f32bc3e6d514b08caf79f2aca..06260874f018f4ff7d5a9d1f8d07cf8ba2e6ca11 100644 (file)
@@ -369,7 +369,7 @@ init_IRQ(void)
 
        /* Point all IRQ's to bad handlers. */
        for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) {
-               irq_desc[j].handler = &crisv32_irq_type;
+               irq_desc[j].chip = &crisv32_irq_type;
                set_exception_vector(i, interrupt[j]);
        }
 
index b504def3e346944cc65fad1a5b55cc391f145eb1..6547bb64636419de268dadcccea8d7b89c84c425 100644 (file)
@@ -69,7 +69,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index 0a26bf6f1cd4280ecd682d6de6a6f0c3c2ddd97c..4f165c93be424545ebcad65ee1d2b10be477f7fe 100644 (file)
@@ -64,10 +64,10 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
  */
 void
 pcibios_align_resource(void *data, struct resource *res,
-                      unsigned long size, unsigned long align)
+                      resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
index 47c08bcd9b24f313e2216d88b97e7e2e58958078..1718429286d4f78ab234eabae56d6bb367f67de1 100644 (file)
@@ -233,7 +233,7 @@ config NR_CPUS
 
 config SCHED_SMT
        bool "SMT (Hyperthreading) scheduler support"
-       depends on SMP
+       depends on X86_HT
        help
          SMT scheduler support improves the CPU scheduler's decision making
          when dealing with Intel Pentium 4 chips with HyperThreading at a
@@ -242,7 +242,7 @@ config SCHED_SMT
 
 config SCHED_MC
        bool "Multi-core scheduler support"
-       depends on SMP
+       depends on X86_HT
        default y
        help
          Multi-core scheduler support improves the CPU scheduler's decision
@@ -529,6 +529,7 @@ config X86_PAE
        bool
        depends on HIGHMEM64G
        default y
+       select RESOURCES_64BIT
 
 # Common NUMA Features
 config NUMA
@@ -737,7 +738,7 @@ config KEXEC
          but it is independent of the system firmware.   And like a reboot
          you can start any kernel with it, not just Linux.
 
-         The name comes from the similiarity to the exec system call.
+         The name comes from the similarity to the exec system call.
 
          It is an ongoing process to be certain the hardware in a machine
          is properly shutdown, so do not be surprised if this code does not
@@ -780,9 +781,23 @@ config HOTPLUG_CPU
          enable suspend on SMP systems. CPUs can be controlled through
          /sys/devices/system/cpu.
 
+config COMPAT_VDSO
+       bool "Compat VDSO support"
+       default y
+       help
+         Map the VDSO to the predictable old-style address too.
+       ---help---
+         Say N here if you are running a sufficiently recent glibc
+         version (2.3.3 or later), to remove the high-mapped
+         VDSO mapping and to exclusively use the randomized VDSO.
+
+         If unsure, say Y.
 
 endmenu
 
+config ARCH_ENABLE_MEMORY_HOTPLUG
+       def_bool y
+       depends on HIGHMEM
 
 menu "Power management options (ACPI, APM)"
        depends on !X86_VOYAGER
index 1c3a809e64217292de3d4ab009b32d9953c0ee19..c80271f8f084c04014d926185cbe896a86fe8d9e 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/fixmap.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
+#include <asm/elf.h>
 
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -54,6 +55,7 @@ void foo(void)
        OFFSET(TI_preempt_count, thread_info, preempt_count);
        OFFSET(TI_addr_limit, thread_info, addr_limit);
        OFFSET(TI_restart_block, thread_info, restart_block);
+       OFFSET(TI_sysenter_return, thread_info, sysenter_return);
        BLANK();
 
        OFFSET(EXEC_DOMAIN_handler, exec_domain, handler);
@@ -69,7 +71,7 @@ void foo(void)
                 sizeof(struct tss_struct));
 
        DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
-       DEFINE(VSYSCALL_BASE, __fix_to_virt(FIX_VSYSCALL));
+       DEFINE(VDSO_PRELINK, VDSO_PRELINK);
 
        OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
 }
index fd0457c9c827f406e9e7f35d490bf7c0c648fe01..e6a2d6b80cdae8a84e72566da1642bff59a7dc7a 100644 (file)
@@ -235,10 +235,10 @@ static void __init init_amd(struct cpuinfo_x86 *c)
                        while ((1 << bits) < c->x86_max_cores)
                                bits++;
                }
-               cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1);
-               phys_proc_id[cpu] >>= bits;
+               c->cpu_core_id = c->phys_proc_id & ((1<<bits)-1);
+               c->phys_proc_id >>= bits;
                printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
-                      cpu, c->x86_max_cores, cpu_core_id[cpu]);
+                      cpu, c->x86_max_cores, c->cpu_core_id);
        }
 #endif
 
index 44f2c5f2dda16a0b8adcb6d0170fd92951a7307e..70c87de582c7a793ab346b60c4416bcdaa3a9f2c 100644 (file)
@@ -294,7 +294,7 @@ void __cpuinit generic_identify(struct cpuinfo_x86 * c)
                        if (c->x86 >= 0x6)
                                c->x86_model += ((tfms >> 16) & 0xF) << 4;
                        c->x86_mask = tfms & 15;
-#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_HT
                        c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0);
 #else
                        c->apicid = (ebx >> 24) & 0xFF;
@@ -319,7 +319,7 @@ void __cpuinit generic_identify(struct cpuinfo_x86 * c)
        early_intel_workaround(c);
 
 #ifdef CONFIG_X86_HT
-       phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
+       c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
 #endif
 }
 
@@ -477,11 +477,9 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
 {
        u32     eax, ebx, ecx, edx;
        int     index_msb, core_bits;
-       int     cpu = smp_processor_id();
 
        cpuid(1, &eax, &ebx, &ecx, &edx);
 
-
        if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
                return;
 
@@ -492,16 +490,17 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
        } else if (smp_num_siblings > 1 ) {
 
                if (smp_num_siblings > NR_CPUS) {
-                       printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
+                       printk(KERN_WARNING "CPU: Unsupported number of the "
+                                       "siblings %d", smp_num_siblings);
                        smp_num_siblings = 1;
                        return;
                }
 
                index_msb = get_count_order(smp_num_siblings);
-               phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
+               c->phys_proc_id = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
 
                printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-                      phys_proc_id[cpu]);
+                      c->phys_proc_id);
 
                smp_num_siblings = smp_num_siblings / c->x86_max_cores;
 
@@ -509,12 +508,12 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
 
                core_bits = get_count_order(c->x86_max_cores);
 
-               cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb) &
+               c->cpu_core_id = phys_pkg_id((ebx >> 24) & 0xFF, index_msb) &
                                               ((1 << core_bits) - 1);
 
                if (c->x86_max_cores > 1)
                        printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-                              cpu_core_id[cpu]);
+                              c->cpu_core_id);
        }
 }
 #endif
@@ -613,6 +612,12 @@ void __cpuinit cpu_init(void)
                set_in_cr4(X86_CR4_TSD);
        }
 
+       /* The CPU hotplug case */
+       if (cpu_gdt_descr->address) {
+               gdt = (struct desc_struct *)cpu_gdt_descr->address;
+               memset(gdt, 0, PAGE_SIZE);
+               goto old_gdt;
+       }
        /*
         * This is a horrible hack to allocate the GDT.  The problem
         * is that cpu_init() is called really early for the boot CPU
@@ -631,7 +636,7 @@ void __cpuinit cpu_init(void)
                                local_irq_enable();
                }
        }
-
+old_gdt:
        /*
         * Initialize the per-CPU GDT with the boot GDT,
         * and set up the GDT descriptor:
index 6c37b4fd8ce285c293306788656b016e83cf3da3..e9f0b928b0a9925e534ddeadb3c868493240df58 100644 (file)
@@ -159,13 +159,13 @@ union l2_cache {
        unsigned val;
 };
 
-static unsigned short assocs[] = {
+static const unsigned short assocs[] = {
        [1] = 1, [2] = 2, [4] = 4, [6] = 8,
        [8] = 16,
        [0xf] = 0xffff // ??
        };
-static unsigned char levels[] = { 1, 1, 2 };
-static unsigned char types[] = { 1, 2, 3 };
+static const unsigned char levels[] = { 1, 1, 2 };
+static const unsigned char types[] = { 1, 2, 3 };
 
 static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
                       union _cpuid4_leaf_ebx *ebx,
@@ -261,7 +261,7 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
        unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
        unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
        unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;
-#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_HT
        unsigned int cpu = (c == &boot_cpu_data) ? 0 : (c - cpu_data);
 #endif
 
@@ -383,14 +383,14 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
 
        if (new_l2) {
                l2 = new_l2;
-#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_HT
                cpu_llc_id[cpu] = l2_id;
 #endif
        }
 
        if (new_l3) {
                l3 = new_l3;
-#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_HT
                cpu_llc_id[cpu] = l3_id;
 #endif
        }
@@ -729,7 +729,7 @@ static void __cpuexit cache_remove_dev(struct sys_device * sys_dev)
        return;
 }
 
-static int cacheinfo_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
@@ -747,7 +747,7 @@ static int cacheinfo_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cacheinfo_cpu_notifier =
+static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier =
 {
     .notifier_call = cacheinfo_cpu_callback,
 };
index a19fcb262dbb64d30120f2e974d6ed7c9a31177b..f54a15268ed730d7a24aba1668d140636fb6d88e 100644 (file)
@@ -18,7 +18,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
         * applications want to get the raw CPUID data, they should access
         * /dev/cpu/<cpu_nr>/cpuid instead.
         */
-       static char *x86_cap_flags[] = {
+       static const char * const x86_cap_flags[] = {
                /* Intel-defined */
                "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
                "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
@@ -62,7 +62,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        };
-       static char *x86_power_flags[] = {
+       static const char * const x86_power_flags[] = {
                "ts",   /* temperature sensor */
                "fid",  /* frequency id control */
                "vid",  /* voltage id control */
@@ -109,9 +109,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
 #ifdef CONFIG_X86_HT
        if (c->x86_max_cores * smp_num_siblings > 1) {
-               seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]);
+               seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
                seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[n]));
-               seq_printf(m, "core id\t\t: %d\n", cpu_core_id[n]);
+               seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
                seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
        }
 #endif
index 1d9a4abcdfc71f034c1c822853049280b32de0a2..f6dfa9fb675c1bfc5eba75ba74317ba2815b6da1 100644 (file)
@@ -183,7 +183,7 @@ static int cpuid_class_cpu_callback(struct notifier_block *nfb, unsigned long ac
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpuid_class_cpu_notifier =
+static struct notifier_block __cpuinitdata cpuid_class_cpu_notifier =
 {
        .notifier_call = cpuid_class_cpu_callback,
 };
index 9202b67c4b2e5cc925b0670d0b3e804dc719abbc..8beb0f07d99966b00206880fb3113db77333edd5 100644 (file)
@@ -601,8 +601,10 @@ efi_initialize_iomem_resources(struct resource *code_resource,
                res->end = res->start + ((md->num_pages << EFI_PAGE_SHIFT) - 1);
                res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
                if (request_resource(&iomem_resource, res) < 0)
-                       printk(KERN_ERR PFX "Failed to allocate res %s : 0x%lx-0x%lx\n",
-                               res->name, res->start, res->end);
+                       printk(KERN_ERR PFX "Failed to allocate res %s : "
+                               "0x%llx-0x%llx\n", res->name,
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end);
                /*
                 * We don't know which region contains kernel data so we try
                 * it repeatedly and let the resource manager test it.
index e6e4506e749acbe079f9196fab1a05a6e333a753..fbdb933251b643b8e726feefe8e350205dbd7396 100644 (file)
@@ -83,6 +83,12 @@ VM_MASK              = 0x00020000
 #define resume_kernel          restore_nocheck
 #endif
 
+#ifdef CONFIG_VM86
+#define resume_userspace_sig   check_userspace
+#else
+#define resume_userspace_sig   resume_userspace
+#endif
+
 #define SAVE_ALL \
        cld; \
        pushl %es; \
@@ -211,6 +217,7 @@ ret_from_exception:
        preempt_stop
 ret_from_intr:
        GET_THREAD_INFO(%ebp)
+check_userspace:
        movl EFLAGS(%esp), %eax         # mix EFLAGS and CS
        movb CS(%esp), %al
        testl $(VM_MASK | 3), %eax
@@ -263,7 +270,12 @@ sysenter_past_esp:
        pushl $(__USER_CS)
        CFI_ADJUST_CFA_OFFSET 4
        /*CFI_REL_OFFSET cs, 0*/
-       pushl $SYSENTER_RETURN
+       /*
+        * Push current_thread_info()->sysenter_return to the stack.
+        * A tiny bit of offset fixup is necessary - 4*4 means the 4 words
+        * pushed above; +8 corresponds to copy_thread's esp0 setting.
+        */
+       pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
        CFI_ADJUST_CFA_OFFSET 4
        CFI_REL_OFFSET eip, 0
 
@@ -415,7 +427,7 @@ work_notifysig:                             # deal with pending signals and
                                        # vm86-space
        xorl %edx, %edx
        call do_notify_resume
-       jmp resume_userspace
+       jmp resume_userspace_sig
 
        ALIGN
 work_notifysig_v86:
@@ -428,7 +440,7 @@ work_notifysig_v86:
        movl %eax, %esp
        xorl %edx, %edx
        call do_notify_resume
-       jmp resume_userspace
+       jmp resume_userspace_sig
 #endif
 
        # perform syscall exit tracing
@@ -515,7 +527,7 @@ ENTRY(irq_entries_start)
  .if vector
        CFI_ADJUST_CFA_OFFSET -4
  .endif
-1:     pushl $vector-256
+1:     pushl $~(vector)
        CFI_ADJUST_CFA_OFFSET 4
        jmp common_interrupt
 .data
@@ -535,7 +547,7 @@ common_interrupt:
 #define BUILD_INTERRUPT(name, nr)      \
 ENTRY(name)                            \
        RING0_INT_FRAME;                \
-       pushl $nr-256;                  \
+       pushl $~(nr);                   \
        CFI_ADJUST_CFA_OFFSET 4;        \
        SAVE_ALL;                       \
        movl %esp,%eax;                 \
index c1a42feba28667cd8e0b7662aafe0fdb79607a23..3c6063671a9f94b4beabb137539880acdc105054 100644 (file)
@@ -132,7 +132,7 @@ void make_8259A_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
        io_apic_irqs &= ~(1<<irq);
-       irq_desc[irq].handler = &i8259A_irq_type;
+       irq_desc[irq].chip = &i8259A_irq_type;
        enable_irq(irq);
 }
 
@@ -386,12 +386,12 @@ void __init init_ISA_irqs (void)
                        /*
                         * 16 old-style INTA-cycle interrupts:
                         */
-                       irq_desc[i].handler = &i8259A_irq_type;
+                       irq_desc[i].chip = &i8259A_irq_type;
                } else {
                        /*
                         * 'high' PCI IRQs filled in on demand
                         */
-                       irq_desc[i].handler = &no_irq_type;
+                       irq_desc[i].chip = &no_irq_type;
                }
        }
 }
index 72ae414e4d4976437fefa8a01e1b38d97fdc0395..ec9ea0269d367fb8c346b883f809ba40d7621b0d 100644 (file)
@@ -581,7 +581,7 @@ static int balanced_irq(void *unused)
        
        /* push everything to CPU 0 to give us a starting point.  */
        for (i = 0 ; i < NR_IRQS ; i++) {
-               pending_irq_cpumask[i] = cpumask_of_cpu(0);
+               irq_desc[i].pending_mask = cpumask_of_cpu(0);
                set_pending_irq(i, cpumask_of_cpu(0));
        }
 
@@ -1205,15 +1205,17 @@ static struct hw_interrupt_type ioapic_edge_type;
 #define IOAPIC_EDGE    0
 #define IOAPIC_LEVEL   1
 
-static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
+static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
-       unsigned idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
+       unsigned idx;
+
+       idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
 
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
                        trigger == IOAPIC_LEVEL)
-               irq_desc[idx].handler = &ioapic_level_type;
+               irq_desc[idx].chip = &ioapic_level_type;
        else
-               irq_desc[idx].handler = &ioapic_edge_type;
+               irq_desc[idx].chip = &ioapic_edge_type;
        set_intr_gate(vector, interrupt[idx]);
 }
 
@@ -1325,7 +1327,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
         * The timer IRQ doesn't have to know that behind the
         * scene we have a 8259A-master in AEOI mode ...
         */
-       irq_desc[0].handler = &ioapic_edge_type;
+       irq_desc[0].chip = &ioapic_edge_type;
 
        /*
         * Add it to the IO-APIC irq-routing table:
@@ -2069,6 +2071,13 @@ static void set_ioapic_affinity_vector (unsigned int vector,
 #endif
 #endif
 
+static int ioapic_retrigger(unsigned int irq)
+{
+       send_IPI_self(IO_APIC_VECTOR(irq));
+
+       return 1;
+}
+
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
  * so we use two separate IRQ descriptors. Edge triggered IRQs can be
@@ -2088,6 +2097,7 @@ static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
 #ifdef CONFIG_SMP
        .set_affinity   = set_ioapic_affinity,
 #endif
+       .retrigger      = ioapic_retrigger,
 };
 
 static struct hw_interrupt_type ioapic_level_type __read_mostly = {
@@ -2101,6 +2111,7 @@ static struct hw_interrupt_type ioapic_level_type __read_mostly = {
 #ifdef CONFIG_SMP
        .set_affinity   = set_ioapic_affinity,
 #endif
+       .retrigger      = ioapic_retrigger,
 };
 
 static inline void init_IO_APIC_traps(void)
@@ -2135,7 +2146,7 @@ static inline void init_IO_APIC_traps(void)
                                make_8259A_irq(irq);
                        else
                                /* Strange. Oh, well.. */
-                               irq_desc[irq].handler = &no_irq_type;
+                               irq_desc[irq].chip = &no_irq_type;
                }
        }
 }
@@ -2351,7 +2362,7 @@ static inline void check_timer(void)
        printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
        disable_8259A_irq(0);
-       irq_desc[0].handler = &lapic_irq_type;
+       irq_desc[0].chip = &lapic_irq_type;
        apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);   /* Fixed mode */
        enable_8259A_irq(0);
 
index 061533e0cb5e8efa284258c3619665a287a786e5..16b4917039672bb3200e82c0325ef2f85134fbd9 100644 (file)
@@ -53,13 +53,19 @@ static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
  */
 fastcall unsigned int do_IRQ(struct pt_regs *regs)
 {      
-       /* high bits used in ret_from_ code */
-       int irq = regs->orig_eax & 0xff;
+       /* high bit used in ret_from_ code */
+       int irq = ~regs->orig_eax;
 #ifdef CONFIG_4KSTACKS
        union irq_ctx *curctx, *irqctx;
        u32 *isp;
 #endif
 
+       if (unlikely((unsigned)irq >= NR_IRQS)) {
+               printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
+                                       __FUNCTION__, irq);
+               BUG();
+       }
+
        irq_enter();
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
        /* Debugging check for stack overflow: is there less than 1KB free? */
@@ -76,6 +82,10 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
        }
 #endif
 
+       if (!irq_desc[irq].handle_irq) {
+               __do_IRQ(irq, regs);
+               goto out_exit;
+       }
 #ifdef CONFIG_4KSTACKS
 
        curctx = (union irq_ctx *) current_thread_info();
@@ -100,8 +110,8 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
                 * softirq checks work in the hardirq context.
                 */
                irqctx->tinfo.preempt_count =
-                       irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK |
-                       curctx->tinfo.preempt_count & SOFTIRQ_MASK;
+                       (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
+                       (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
 
                asm volatile(
                        "       xchgl   %%ebx,%%esp      \n"
@@ -115,6 +125,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
 #endif
                __do_IRQ(irq, regs);
 
+out_exit:
        irq_exit();
 
        return 1;
@@ -243,7 +254,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -285,13 +296,13 @@ void fixup_irqs(cpumask_t map)
                if (irq == 2)
                        continue;
 
-               cpus_and(mask, irq_affinity[irq], map);
+               cpus_and(mask, irq_desc[irq].affinity, map);
                if (any_online_cpu(mask) == NR_CPUS) {
                        printk("Breaking affinity for irq %i\n", irq);
                        mask = map;
                }
-               if (irq_desc[irq].handler->set_affinity)
-                       irq_desc[irq].handler->set_affinity(irq, mask);
+               if (irq_desc[irq].chip->set_affinity)
+                       irq_desc[irq].chip->set_affinity(irq, mask);
                else if (irq_desc[irq].action && !(warned++))
                        printk("Cannot set affinity for irq %i\n", irq);
        }
index 0a865889b2a993ccfe409dbfd219a262a295dffc..40b44cc0d14b048523f8bbf0c6935342a6067e3e 100644 (file)
@@ -493,7 +493,6 @@ static struct file_operations microcode_fops = {
 static struct miscdevice microcode_dev = {
        .minor          = MICROCODE_MINOR,
        .name           = "microcode",
-       .devfs_name     = "cpu/microcode",
        .fops           = &microcode_fops,
 };
 
index 7a328230e540f8b073e5d0306f457a1a9bffbc28..d022cb8fd7251ccc79e3eeb89a8210e5f92b85d1 100644 (file)
@@ -266,7 +266,7 @@ static int msr_class_cpu_callback(struct notifier_block *nfb, unsigned long acti
        return NOTIFY_OK;
 }
 
-static struct notifier_block msr_class_cpu_notifier =
+static struct notifier_block __cpuinitdata msr_class_cpu_notifier =
 {
        .notifier_call = msr_class_cpu_callback,
 };
index 321f5fd26e75062ef2119710e9ce1b7047ac662c..9bf590cefc7d4d55d89fde0561ec6a5fb70d5192 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 
 #include <linux/scx200.h>
@@ -45,11 +46,19 @@ static struct pci_driver scx200_pci_driver = {
        .probe = scx200_probe,
 };
 
-static DEFINE_SPINLOCK(scx200_gpio_config_lock);
+static DEFINE_MUTEX(scx200_gpio_config_lock);
 
-static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static void __devinit scx200_init_shadow(void)
 {
        int bank;
+
+       /* read the current values driven on the GPIO signals */
+       for (bank = 0; bank < 2; ++bank)
+               scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
+}
+
+static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
        unsigned base;
 
        if (pdev->device == PCI_DEVICE_ID_NS_SCx200_BRIDGE ||
@@ -63,10 +72,7 @@ static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_
                }
 
                scx200_gpio_base = base;
-
-               /* read the current values driven on the GPIO signals */
-               for (bank = 0; bank < 2; ++bank)
-                       scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
+               scx200_init_shadow();
 
        } else {
                /* find the base of the Configuration Block */
@@ -87,12 +93,11 @@ static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_
        return 0;
 }
 
-u32 scx200_gpio_configure(int index, u32 mask, u32 bits)
+u32 scx200_gpio_configure(unsigned index, u32 mask, u32 bits)
 {
        u32 config, new_config;
-       unsigned long flags;
 
-       spin_lock_irqsave(&scx200_gpio_config_lock, flags);
+       mutex_lock(&scx200_gpio_config_lock);
 
        outl(index, scx200_gpio_base + 0x20);
        config = inl(scx200_gpio_base + 0x24);
@@ -100,45 +105,11 @@ u32 scx200_gpio_configure(int index, u32 mask, u32 bits)
        new_config = (config & mask) | bits;
        outl(new_config, scx200_gpio_base + 0x24);
 
-       spin_unlock_irqrestore(&scx200_gpio_config_lock, flags);
+       mutex_unlock(&scx200_gpio_config_lock);
 
        return config;
 }
 
-#if 0
-void scx200_gpio_dump(unsigned index)
-{
-       u32 config = scx200_gpio_configure(index, ~0, 0);
-       printk(KERN_DEBUG "GPIO%02u: 0x%08lx", index, (unsigned long)config);
-       
-       if (config & 1) 
-               printk(" OE"); /* output enabled */
-       else
-               printk(" TS"); /* tristate */
-       if (config & 2) 
-               printk(" PP"); /* push pull */
-       else
-               printk(" OD"); /* open drain */
-       if (config & 4) 
-               printk(" PUE"); /* pull up enabled */
-       else
-               printk(" PUD"); /* pull up disabled */
-       if (config & 8) 
-               printk(" LOCKED"); /* locked */
-       if (config & 16) 
-               printk(" LEVEL"); /* level input */
-       else
-               printk(" EDGE"); /* edge input */
-       if (config & 32) 
-               printk(" HI"); /* trigger on rising edge */
-       else
-               printk(" LO"); /* trigger on falling edge */
-       if (config & 64) 
-               printk(" DEBOUNCE"); /* debounce */
-       printk("\n");
-}
-#endif  /*  0  */
-
 static int __init scx200_init(void)
 {
        printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");
@@ -159,10 +130,3 @@ EXPORT_SYMBOL(scx200_gpio_base);
 EXPORT_SYMBOL(scx200_gpio_shadow);
 EXPORT_SYMBOL(scx200_gpio_configure);
 EXPORT_SYMBOL(scx200_cb_base);
-
-/*
-    Local variables:
-        compile-command: "make -k -C ../../.. SUBDIRS=arch/i386/kernel modules"
-        c-basic-offset: 8
-    End:
-*/
index 4a65040cc624b06bf1de3ca678f66cd9527b36a9..6712f0d2eb37372aa040ce352ef68a9ebd8c09d7 100644 (file)
@@ -1314,8 +1314,10 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat
        probe_roms();
        for (i = 0; i < e820.nr_map; i++) {
                struct resource *res;
+#ifndef CONFIG_RESOURCES_64BIT
                if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
                        continue;
+#endif
                res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
                switch (e820.map[i].type) {
                case E820_RAM:  res->name = "System RAM"; break;
index 5c352c3a9e7fa00492da1ff1c33a28ad0b5217c7..43002cfb40c4e2811bf5006c9126fa2ff1cfdd46 100644 (file)
@@ -351,7 +351,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,
                        goto give_sigsegv;
        }
 
-       restorer = &__kernel_sigreturn;
+       restorer = (void *)VDSO_SYM(&__kernel_sigreturn);
        if (ka->sa.sa_flags & SA_RESTORER)
                restorer = ka->sa.sa_restorer;
 
@@ -447,7 +447,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                goto give_sigsegv;
 
        /* Set up to return from userspace.  */
-       restorer = &__kernel_rt_sigreturn;
+       restorer = (void *)VDSO_SYM(&__kernel_rt_sigreturn);
        if (ka->sa.sa_flags & SA_RESTORER)
                restorer = ka->sa.sa_restorer;
        err |= __put_user(restorer, &frame->pretcode);
index bce5470ecb42e6e91ac47510366676fe13637a57..89e7315e539c49a5f8f19a3479ae21774075a374 100644 (file)
@@ -67,12 +67,6 @@ int smp_num_siblings = 1;
 EXPORT_SYMBOL(smp_num_siblings);
 #endif
 
-/* Package ID of each logical CPU */
-int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
-
-/* Core ID of each logical CPU */
-int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
-
 /* Last level cache ID of each logical CPU */
 int cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID};
 
@@ -454,10 +448,12 @@ cpumask_t cpu_coregroup_map(int cpu)
        struct cpuinfo_x86 *c = cpu_data + cpu;
        /*
         * For perf, we return last level cache shared map.
-        * TBD: when power saving sched policy is added, we will return
-        *      cpu_core_map when power saving policy is enabled
+        * And for power savings, we return cpu_core_map
         */
-       return c->llc_shared_map;
+       if (sched_mc_power_savings || sched_smt_power_savings)
+               return cpu_core_map[cpu];
+       else
+               return c->llc_shared_map;
 }
 
 /* representing cpus for which sibling maps can be computed */
@@ -473,8 +469,8 @@ set_cpu_sibling_map(int cpu)
 
        if (smp_num_siblings > 1) {
                for_each_cpu_mask(i, cpu_sibling_setup_map) {
-                       if (phys_proc_id[cpu] == phys_proc_id[i] &&
-                           cpu_core_id[cpu] == cpu_core_id[i]) {
+                       if (c[cpu].phys_proc_id == c[i].phys_proc_id &&
+                           c[cpu].cpu_core_id == c[i].cpu_core_id) {
                                cpu_set(i, cpu_sibling_map[cpu]);
                                cpu_set(cpu, cpu_sibling_map[i]);
                                cpu_set(i, cpu_core_map[cpu]);
@@ -501,7 +497,7 @@ set_cpu_sibling_map(int cpu)
                        cpu_set(i, c[cpu].llc_shared_map);
                        cpu_set(cpu, c[i].llc_shared_map);
                }
-               if (phys_proc_id[cpu] == phys_proc_id[i]) {
+               if (c[cpu].phys_proc_id == c[i].phys_proc_id) {
                        cpu_set(i, cpu_core_map[cpu]);
                        cpu_set(cpu, cpu_core_map[i]);
                        /*
@@ -1056,6 +1052,7 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
        struct warm_boot_cpu_info info;
        struct work_struct task;
        int     apicid, ret;
+       struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
 
        apicid = x86_cpu_to_apicid[cpu];
        if (apicid == BAD_APICID) {
@@ -1063,6 +1060,18 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
                goto exit;
        }
 
+       /*
+        * the CPU isn't initialized at boot time, allocate gdt table here.
+        * cpu_init will initialize it
+        */
+       if (!cpu_gdt_descr->address) {
+               cpu_gdt_descr->address = get_zeroed_page(GFP_KERNEL);
+               if (!cpu_gdt_descr->address)
+                       printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu);
+                       ret = -ENOMEM;
+                       goto exit;
+       }
+
        info.complete = &done;
        info.apicid = apicid;
        info.cpu = cpu;
@@ -1340,8 +1349,8 @@ remove_siblinginfo(int cpu)
                cpu_clear(cpu, cpu_sibling_map[sibling]);
        cpus_clear(cpu_sibling_map[cpu]);
        cpus_clear(cpu_core_map[cpu]);
-       phys_proc_id[cpu] = BAD_APICID;
-       cpu_core_id[cpu] = BAD_APICID;
+       c[cpu].phys_proc_id = 0;
+       c[cpu].cpu_core_id = 0;
        cpu_clear(cpu, cpu_sibling_setup_map);
 }
 
index 0bada1870bdf5691631e10558bf43cbb350691a1..713ba39d32c66db0e2ad4ca0580088ffccef785f 100644 (file)
@@ -2,6 +2,8 @@
  * linux/arch/i386/kernel/sysenter.c
  *
  * (C) Copyright 2002 Linus Torvalds
+ * Portions based on the vdso-randomization code from exec-shield:
+ * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
  *
  * This file contains the needed initializations to support sysenter.
  */
 #include <linux/gfp.h>
 #include <linux/string.h>
 #include <linux/elf.h>
+#include <linux/mm.h>
+#include <linux/module.h>
 
 #include <asm/cpufeature.h>
 #include <asm/msr.h>
 #include <asm/pgtable.h>
 #include <asm/unistd.h>
 
+/*
+ * Should the kernel map a VDSO page into processes and pass its
+ * address down to glibc upon exec()?
+ */
+unsigned int __read_mostly vdso_enabled = 1;
+
+EXPORT_SYMBOL_GPL(vdso_enabled);
+
+static int __init vdso_setup(char *s)
+{
+       vdso_enabled = simple_strtoul(s, NULL, 0);
+
+       return 1;
+}
+
+__setup("vdso=", vdso_setup);
+
 extern asmlinkage void sysenter_entry(void);
 
 void enable_sep_cpu(void)
@@ -45,23 +66,120 @@ void enable_sep_cpu(void)
  */
 extern const char vsyscall_int80_start, vsyscall_int80_end;
 extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
+static void *syscall_page;
 
 int __init sysenter_setup(void)
 {
-       void *page = (void *)get_zeroed_page(GFP_ATOMIC);
+       syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
 
-       __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY_EXEC);
+#ifdef CONFIG_COMPAT_VDSO
+       __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY);
+       printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
+#else
+       /*
+        * In the non-compat case the ELF coredumping code needs the fixmap:
+        */
+       __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_KERNEL_RO);
+#endif
 
        if (!boot_cpu_has(X86_FEATURE_SEP)) {
-               memcpy(page,
+               memcpy(syscall_page,
                       &vsyscall_int80_start,
                       &vsyscall_int80_end - &vsyscall_int80_start);
                return 0;
        }
 
-       memcpy(page,
+       memcpy(syscall_page,
               &vsyscall_sysenter_start,
               &vsyscall_sysenter_end - &vsyscall_sysenter_start);
 
        return 0;
 }
+
+static struct page *syscall_nopage(struct vm_area_struct *vma,
+                               unsigned long adr, int *type)
+{
+       struct page *p = virt_to_page(adr - vma->vm_start + syscall_page);
+       get_page(p);
+       return p;
+}
+
+/* Prevent VMA merging */
+static void syscall_vma_close(struct vm_area_struct *vma)
+{
+}
+
+static struct vm_operations_struct syscall_vm_ops = {
+       .close = syscall_vma_close,
+       .nopage = syscall_nopage,
+};
+
+/* Defined in vsyscall-sysenter.S */
+extern void SYSENTER_RETURN;
+
+/* Setup a VMA at program startup for the vsyscall page */
+int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
+{
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = current->mm;
+       unsigned long addr;
+       int ret;
+
+       down_write(&mm->mmap_sem);
+       addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+       if (IS_ERR_VALUE(addr)) {
+               ret = addr;
+               goto up_fail;
+       }
+
+       vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL);
+       if (!vma) {
+               ret = -ENOMEM;
+               goto up_fail;
+       }
+
+       vma->vm_start = addr;
+       vma->vm_end = addr + PAGE_SIZE;
+       /* MAYWRITE to allow gdb to COW and set breakpoints */
+       vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
+       vma->vm_flags |= mm->def_flags;
+       vma->vm_page_prot = protection_map[vma->vm_flags & 7];
+       vma->vm_ops = &syscall_vm_ops;
+       vma->vm_mm = mm;
+
+       ret = insert_vm_struct(mm, vma);
+       if (unlikely(ret)) {
+               kmem_cache_free(vm_area_cachep, vma);
+               goto up_fail;
+       }
+
+       current->mm->context.vdso = (void *)addr;
+       current_thread_info()->sysenter_return =
+                                   (void *)VDSO_SYM(&SYSENTER_RETURN);
+       mm->total_vm++;
+up_fail:
+       up_write(&mm->mmap_sem);
+       return ret;
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+       if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
+               return "[vdso]";
+       return NULL;
+}
+
+struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+{
+       return NULL;
+}
+
+int in_gate_area(struct task_struct *task, unsigned long addr)
+{
+       return 0;
+}
+
+int in_gate_area_no_task(unsigned long addr)
+{
+       return 0;
+}
index 296355292c7c56433df1c849e93851985a7798d3..e2e281d4bcc80ee7bc3b090e75914606231e6224 100644 (file)
 
 static struct i386_cpu cpu_devices[NR_CPUS];
 
-int arch_register_cpu(int num){
-       struct node *parent = NULL;
-
-#ifdef CONFIG_NUMA
-       int node = cpu_to_node(num);
-       if (node_online(node))
-               parent = &node_devices[node].node;
-#endif /* CONFIG_NUMA */
-
+int arch_register_cpu(int num)
+{
        /*
         * CPU0 cannot be offlined due to several
         * restrictions and assumptions in kernel. This basically
@@ -50,21 +43,13 @@ int arch_register_cpu(int num){
        if (!num)
                cpu_devices[num].cpu.no_control = 1;
 
-       return register_cpu(&cpu_devices[num].cpu, num, parent);
+       return register_cpu(&cpu_devices[num].cpu, num);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
 
 void arch_unregister_cpu(int num) {
-       struct node *parent = NULL;
-
-#ifdef CONFIG_NUMA
-       int node = cpu_to_node(num);
-       if (node_online(node))
-               parent = &node_devices[node].node;
-#endif /* CONFIG_NUMA */
-
-       return unregister_cpu(&cpu_devices[num].cpu, parent);
+       return unregister_cpu(&cpu_devices[num].cpu);
 }
 EXPORT_SYMBOL(arch_register_cpu);
 EXPORT_SYMBOL(arch_unregister_cpu);
@@ -74,16 +59,13 @@ EXPORT_SYMBOL(arch_unregister_cpu);
 
 #ifdef CONFIG_NUMA
 #include <linux/mmzone.h>
-#include <asm/node.h>
-
-struct i386_node node_devices[MAX_NUMNODES];
 
 static int __init topology_init(void)
 {
        int i;
 
        for_each_online_node(i)
-               arch_register_node(i);
+               register_one_node(i);
 
        for_each_present_cpu(i)
                arch_register_cpu(i);
index 3b62baa6a371def2c0ae3e426fbf2410f3fc83a2..1a36d26e15eb0c6d370832ee166dd0fba3700f59 100644 (file)
@@ -42,10 +42,10 @@ __kernel_vsyscall:
        /* 7: align return point with nop's to make disassembly easier */
        .space 7,0x90
 
-       /* 14: System call restart point is here! (SYSENTER_RETURN - 2) */
+       /* 14: System call restart point is here! (SYSENTER_RETURN-2) */
        jmp .Lenter_kernel
        /* 16: System call normal return point is here! */
-       .globl SYSENTER_RETURN  /* Symbol used by entry.S.  */
+       .globl SYSENTER_RETURN  /* Symbol used by sysenter.c  */
 SYSENTER_RETURN:
        pop %ebp
 .Lpop_ebp:
index 98699ca6e52d7b2febba30a086741a4f663da426..e26975fc68b650105cbff7b0568ba7b856770085 100644 (file)
@@ -7,7 +7,7 @@
 
 SECTIONS
 {
-  . = VSYSCALL_BASE + SIZEOF_HEADERS;
+  . = VDSO_PRELINK + SIZEOF_HEADERS;
 
   .hash           : { *(.hash) }               :text
   .dynsym         : { *(.dynsym) }
@@ -20,7 +20,7 @@ SECTIONS
      For the layouts to match, we need to skip more than enough
      space for the dynamic symbol table et al.  If this amount
      is insufficient, ld -shared will barf.  Just increase it here.  */
-  . = VSYSCALL_BASE + 0x400;
+  . = VDSO_PRELINK + 0x400;
 
   .text           : { *(.text) }               :text =0x90909090
   .note                  : { *(.note.*) }              :text :note
index 8a9e1a6f745de17f9d28e9acfaf2e3f3d205994a..1f84cdb24779179b77da4b80d711ae6f276f5d5f 100644 (file)
@@ -140,8 +140,8 @@ void __init time_init_hook(void)
 
 #define MB (1024 * 1024)
 
-static unsigned long sgivwfb_mem_phys;
-static unsigned long sgivwfb_mem_size;
+unsigned long sgivwfb_mem_phys;
+unsigned long sgivwfb_mem_size;
 
 long long mem_size __initdata = 0;
 
@@ -177,8 +177,4 @@ char * __init machine_specific_memory_setup(void)
        add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
 
        return "PROM";
-
-       /* Remove gcc warnings */
-       (void) sanitize_e820_map(NULL, NULL);
-       (void) copy_e820_map(NULL, 0);
 }
index 3e64fb7212911bc4db9fe8db9f67ab75a40ecd36..c418521dd5547073cf78bfbf0e9bb710366cb3b0 100644 (file)
@@ -278,22 +278,22 @@ void init_VISWS_APIC_irqs(void)
                irq_desc[i].depth = 1;
 
                if (i == 0) {
-                       irq_desc[i].handler = &cobalt_irq_type;
+                       irq_desc[i].chip = &cobalt_irq_type;
                }
                else if (i == CO_IRQ_IDE0) {
-                       irq_desc[i].handler = &cobalt_irq_type;
+                       irq_desc[i].chip = &cobalt_irq_type;
                }
                else if (i == CO_IRQ_IDE1) {
-                       irq_desc[i].handler = &cobalt_irq_type;
+                       irq_desc[i].chip = &cobalt_irq_type;
                }
                else if (i == CO_IRQ_8259) {
-                       irq_desc[i].handler = &piix4_master_irq_type;
+                       irq_desc[i].chip = &piix4_master_irq_type;
                }
                else if (i < CO_IRQ_APIC0) {
-                       irq_desc[i].handler = &piix4_virtual_irq_type;
+                       irq_desc[i].chip = &piix4_virtual_irq_type;
                }
                else if (IS_CO_APIC(i)) {
-                       irq_desc[i].handler = &cobalt_irq_type;
+                       irq_desc[i].chip = &cobalt_irq_type;
                }
        }
 
index 0e225054e2229cf9543f70ede0b5794e45ddb73d..defc6ebbd56517ac054deeeafbf17239de36cc5d 100644 (file)
@@ -5,10 +5,10 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/acpi.h>
 #include <asm/arch_hooks.h>
 #include <asm/voyager.h>
 #include <asm/e820.h>
+#include <asm/io.h>
 #include <asm/setup.h>
 
 void __init pre_intr_init_hook(void)
@@ -27,8 +27,7 @@ void __init intr_init_hook(void)
        smp_intr_init();
 #endif
 
-       if (!acpi_ioapic)
-               setup_irq(2, &irq2);
+       setup_irq(2, &irq2);
 }
 
 void __init pre_setup_arch_hook(void)
index 70e560a1b79ad1c457d0ac9777d3931d2c8ba87a..5b8b579a079fa8a7afdc52e4871aef91b3a94665 100644 (file)
@@ -661,6 +661,7 @@ do_boot_cpu(__u8 cpu)
                print_cpu_info(&cpu_data[cpu]);
                wmb();
                cpu_set(cpu, cpu_callout_map);
+               cpu_set(cpu, cpu_present_map);
        }
        else {
                printk("CPU%d FAILED TO BOOT: ", cpu);
@@ -1418,7 +1419,7 @@ smp_intr_init(void)
         * This is for later: first 16 correspond to PC IRQs; next 16
         * are Primary MC IRQs and final 16 are Secondary MC IRQs */
        for(i = 0; i < 48; i++)
-               irq_desc[i].handler = &vic_irq_type;
+               irq_desc[i].chip = &vic_irq_type;
 }
 
 /* send a CPI at level cpi to a set of cpus in cpuset (set 1 bit per
@@ -1912,6 +1913,7 @@ void __devinit smp_prepare_boot_cpu(void)
        cpu_set(smp_processor_id(), cpu_online_map);
        cpu_set(smp_processor_id(), cpu_callout_map);
        cpu_set(smp_processor_id(), cpu_possible_map);
+       cpu_set(smp_processor_id(), cpu_present_map);
 }
 
 int __devinit
index bf19513f0cea227126407b0e22cbb0bf614fa7b3..f84b16e007ff86fb73185482efcbca7be8eb4ebd 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
+#include <linux/poison.h>
 #include <linux/bootmem.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
@@ -654,7 +655,7 @@ void __init mem_init(void)
  */
 #ifdef CONFIG_MEMORY_HOTPLUG
 #ifndef CONFIG_NEED_MULTIPLE_NODES
-int add_memory(u64 start, u64 size)
+int arch_add_memory(int nid, u64 start, u64 size)
 {
        struct pglist_data *pgdata = &contig_page_data;
        struct zone *zone = pgdata->node_zones + MAX_NR_ZONES-1;
@@ -753,7 +754,7 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
        for (addr = begin; addr < end; addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
                init_page_count(virt_to_page(addr));
-               memset((void *)addr, 0xcc, PAGE_SIZE);
+               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
                free_page(addr);
                totalram_pages++;
        }
index 0887b34bc59b987543c10b92ae53d73b83c361ef..353a836ed63c03f363acbcba49e4c54d9258f855 100644 (file)
@@ -229,8 +229,8 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
        if (PageHighMem(page))
                return;
        if (!enable)
-               mutex_debug_check_no_locks_freed(page_address(page),
-                                                numpages * PAGE_SIZE);
+               debug_check_no_locks_freed(page_address(page),
+                                          numpages * PAGE_SIZE);
 
        /* the return value is ignored - the calls cannot fail,
         * large pages are disabled at boot time.
index a151f7a99f5e8010a7f9875cede3f9aceb81ed61..10154a2cac6895d6073973f3e12ef95d18bee247 100644 (file)
  */
 void
 pcibios_align_resource(void *data, struct resource *res,
-                      unsigned long size, unsigned long align)
+                       resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
index 18318749884b012f1f2e3d879a633a7ed21802bd..b487e227a1f7a3e6b17dd48d57a81d1319e0e376 100644 (file)
@@ -271,6 +271,9 @@ config HOTPLUG_CPU
          can be controlled through /sys/devices/system/cpu/cpu#.
          Say N if you want to disable CPU hotplug.
 
+config ARCH_ENABLE_MEMORY_HOTPLUG
+       def_bool y
+
 config SCHED_SMT
        bool "SMT scheduler support"
        depends on SMP
@@ -374,6 +377,10 @@ config HAVE_ARCH_EARLY_PFN_TO_NID
        def_bool y
        depends on NEED_MULTIPLE_NODES
 
+config HAVE_ARCH_NODEDATA_EXTENSION
+       def_bool y
+       depends on NUMA
+
 config IA32_SUPPORT
        bool "Support for Linux/x86 binaries"
        help
@@ -485,6 +492,10 @@ config GENERIC_PENDING_IRQ
        depends on GENERIC_HARDIRQS && SMP
        default y
 
+config IRQ_PER_CPU
+       bool
+       default y
+
 source "arch/ia64/hp/sim/Kconfig"
 
 menu "Instrumentation Support"
index 766bf495543249e44bfd69d92a31ebd3a69b47cc..9d1cffb57cde20c3f143a529b8bd5a2d6cf114a5 100644 (file)
@@ -114,7 +114,7 @@ CONFIG_IA64_CYCLONE=y
 CONFIG_IOSAPIC=y
 CONFIG_FORCE_MAX_ZONEORDER=17
 CONFIG_SMP=y
-CONFIG_NR_CPUS=4
+CONFIG_NR_CPUS=16
 CONFIG_HOTPLUG_CPU=y
 CONFIG_PERMIT_BSP_REMOVE=y
 CONFIG_FORCE_CPEI_RETARGET=y
index c0d25a2a3e9caf1ddbf7eb396b23027347024856..8145547bb52daf891199affd969a5dd9cb8cee9a 100644 (file)
@@ -44,8 +44,8 @@ hpsim_irq_init (void)
        int i;
 
        for (i = 0; i < NR_IRQS; ++i) {
-               idesc = irq_descp(i);
-               if (idesc->handler == &no_irq_type)
-                       idesc->handler = &irq_type_hp_sim;
+               idesc = irq_desc + i;
+               if (idesc->chip == &no_irq_type)
+                       idesc->chip = &irq_type_hp_sim;
        }
 }
index d58c1c5c903a9cfdae0981411ae53604fce020f1..efc7df4b0fd251a126b29a263546bb4ef2181f07 100644 (file)
@@ -456,7 +456,7 @@ iosapic_startup_edge_irq (unsigned int irq)
 static void
 iosapic_ack_edge_irq (unsigned int irq)
 {
-       irq_desc_t *idesc = irq_descp(irq);
+       irq_desc_t *idesc = irq_desc + irq;
 
        move_native_irq(irq);
        /*
@@ -659,14 +659,14 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
        else
                irq_type = &irq_type_iosapic_level;
 
-       idesc = irq_descp(vector);
-       if (idesc->handler != irq_type) {
-               if (idesc->handler != &no_irq_type)
+       idesc = irq_desc + vector;
+       if (idesc->chip != irq_type) {
+               if (idesc->chip != &no_irq_type)
                        printk(KERN_WARNING
                               "%s: changing vector %d from %s to %s\n",
                               __FUNCTION__, vector,
-                              idesc->handler->typename, irq_type->typename);
-               idesc->handler = irq_type;
+                              idesc->chip->typename, irq_type->typename);
+               idesc->chip = irq_type;
        }
        return 0;
 }
@@ -793,14 +793,14 @@ again:
                        return -ENOSPC;
        }
 
-       spin_lock_irqsave(&irq_descp(vector)->lock, flags);
+       spin_lock_irqsave(&irq_desc[vector].lock, flags);
        spin_lock(&iosapic_lock);
        {
                if (gsi_to_vector(gsi) > 0) {
                        if (list_empty(&iosapic_intr_info[vector].rtes))
                                free_irq_vector(vector);
                        spin_unlock(&iosapic_lock);
-                       spin_unlock_irqrestore(&irq_descp(vector)->lock,
+                       spin_unlock_irqrestore(&irq_desc[vector].lock,
                                               flags);
                        goto again;
                }
@@ -810,7 +810,7 @@ again:
                              polarity, trigger);
                if (err < 0) {
                        spin_unlock(&iosapic_lock);
-                       spin_unlock_irqrestore(&irq_descp(vector)->lock,
+                       spin_unlock_irqrestore(&irq_desc[vector].lock,
                                               flags);
                        return err;
                }
@@ -825,7 +825,7 @@ again:
                set_rte(gsi, vector, dest, mask);
        }
        spin_unlock(&iosapic_lock);
-       spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+       spin_unlock_irqrestore(&irq_desc[vector].lock, flags);
 
        printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
               gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
@@ -860,7 +860,7 @@ iosapic_unregister_intr (unsigned int gsi)
        }
        vector = irq_to_vector(irq);
 
-       idesc = irq_descp(irq);
+       idesc = irq_desc + irq;
        spin_lock_irqsave(&idesc->lock, flags);
        spin_lock(&iosapic_lock);
        {
@@ -903,7 +903,7 @@ iosapic_unregister_intr (unsigned int gsi)
                        BUG_ON(iosapic_intr_info[vector].count);
 
                        /* Clear the interrupt controller descriptor */
-                       idesc->handler = &no_irq_type;
+                       idesc->chip = &no_irq_type;
 
                        /* Clear the interrupt information */
                        memset(&iosapic_intr_info[vector], 0,
index 9c72ea3f6432d115ca32090d0c8bd9c8365d5c07..7852382de2fa6666a67383086f0014c93ddce43a 100644 (file)
@@ -76,7 +76,7 @@ int show_interrupts(struct seq_file *p, void *v)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
                }
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -100,7 +100,7 @@ void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
        cpu_set(cpu_logical_id(hwid), mask);
 
        if (irq < NR_IRQS) {
-               irq_affinity[irq] = mask;
+               irq_desc[irq].affinity = mask;
                irq_redir[irq] = (char) (redir & 0xff);
        }
 }
@@ -120,7 +120,7 @@ static void migrate_irqs(void)
        int             irq, new_cpu;
 
        for (irq=0; irq < NR_IRQS; irq++) {
-               desc = irq_descp(irq);
+               desc = irq_desc + irq;
 
                /*
                 * No handling for now.
@@ -131,7 +131,7 @@ static void migrate_irqs(void)
                if (desc->status == IRQ_PER_CPU)
                        continue;
 
-               cpus_and(mask, irq_affinity[irq], cpu_online_map);
+               cpus_and(mask, irq_desc[irq].affinity, cpu_online_map);
                if (any_online_cpu(mask) == NR_CPUS) {
                        /*
                         * Save it for phase 2 processing
@@ -144,15 +144,15 @@ static void migrate_irqs(void)
                        /*
                         * Al three are essential, currently WARN_ON.. maybe panic?
                         */
-                       if (desc->handler && desc->handler->disable &&
-                               desc->handler->enable && desc->handler->set_affinity) {
-                               desc->handler->disable(irq);
-                               desc->handler->set_affinity(irq, mask);
-                               desc->handler->enable(irq);
+                       if (desc->chip && desc->chip->disable &&
+                               desc->chip->enable && desc->chip->set_affinity) {
+                               desc->chip->disable(irq);
+                               desc->chip->set_affinity(irq, mask);
+                               desc->chip->enable(irq);
                        } else {
-                               WARN_ON((!(desc->handler) || !(desc->handler->disable) ||
-                                               !(desc->handler->enable) ||
-                                               !(desc->handler->set_affinity)));
+                               WARN_ON((!(desc->chip) || !(desc->chip->disable) ||
+                                               !(desc->chip->enable) ||
+                                               !(desc->chip->set_affinity)));
                        }
                }
        }
index ef9a2b49307ae756ac58a8fb7f8c360aa2aca53a..f5035304594e5af977d6b432a3f82e45b9320d93 100644 (file)
@@ -249,9 +249,9 @@ register_percpu_irq (ia64_vector vec, struct irqaction *action)
 
        for (irq = 0; irq < NR_IRQS; ++irq)
                if (irq_to_vector(irq) == vec) {
-                       desc = irq_descp(irq);
+                       desc = irq_desc + irq;
                        desc->status |= IRQ_PER_CPU;
-                       desc->handler = &irq_type_ia64_lsapic;
+                       desc->chip = &irq_type_ia64_lsapic;
                        if (action)
                                setup_irq(irq, action);
                }
index ea14e6a04409636c62813048504cf77e3ef57949..1ab58b09f3d7163df640f5765efd7d8d3a020c02 100644 (file)
@@ -26,6 +26,13 @@ lsapic_noop (unsigned int irq)
        /* nuthing to do... */
 }
 
+static int lsapic_retrigger(unsigned int irq)
+{
+       ia64_resend_irq(irq);
+
+       return 1;
+}
+
 struct hw_interrupt_type irq_type_ia64_lsapic = {
        .typename =     "LSAPIC",
        .startup =      lsapic_noop_startup,
@@ -33,5 +40,6 @@ struct hw_interrupt_type irq_type_ia64_lsapic = {
        .enable =       lsapic_noop,
        .disable =      lsapic_noop,
        .ack =          lsapic_noop,
-       .end =          lsapic_noop
+       .end =          lsapic_noop,
+       .retrigger =    lsapic_retrigger,
 };
index 6a0880639bc9396208c30a9f9ccd4b3ae93aa835..d7dc5e63de63c2bc29b9a1fc19b98c663517de5f 100644 (file)
@@ -1788,7 +1788,7 @@ ia64_mca_late_init(void)
                        cpe_poll_enabled = 0;
                        for (irq = 0; irq < NR_IRQS; ++irq)
                                if (irq_to_vector(irq) == cpe_vector) {
-                                       desc = irq_descp(irq);
+                                       desc = irq_desc + irq;
                                        desc->status |= IRQ_PER_CPU;
                                        setup_irq(irq, &mca_cpe_irqaction);
                                        ia64_cpe_irq = irq;
index 859fb37ff49b682799b65b1384b9d05cbc576b88..8a12084191384ee55f02ed5848a95ef708206732 100644 (file)
@@ -959,7 +959,7 @@ remove_palinfo_proc_entries(unsigned int hcpu)
        }
 }
 
-static int palinfo_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
                                                                unsigned long action,
                                                                void *hcpu)
 {
@@ -978,7 +978,7 @@ static int palinfo_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block palinfo_cpu_notifier =
+static struct notifier_block __cpuinitdata palinfo_cpu_notifier =
 {
        .notifier_call = palinfo_cpu_callback,
        .priority = 0,
@@ -998,7 +998,7 @@ palinfo_init(void)
        }
 
        /* Register for future delivery via notify registration */
-       register_cpu_notifier(&palinfo_cpu_notifier);
+       register_hotcpu_notifier(&palinfo_cpu_notifier);
 
        return 0;
 }
index 6d7bc8ff7b3afff19b3781cdaa91a18d27268772..a0055d3d695c81d2ba042dcbe54d831ffd82a42b 100644 (file)
@@ -6165,7 +6165,7 @@ pfm_load_regs (struct task_struct *task)
                /*
                 * will replay the PMU interrupt
                 */
-               if (need_irq_resend) hw_resend_irq(NULL, IA64_PERFMON_VECTOR);
+               if (need_irq_resend) ia64_resend_irq(IA64_PERFMON_VECTOR);
 
                pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++;
        }
@@ -6305,7 +6305,7 @@ pfm_load_regs (struct task_struct *task)
                /*
                 * will replay the PMU interrupt
                 */
-               if (need_irq_resend) hw_resend_irq(NULL, IA64_PERFMON_VECTOR);
+               if (need_irq_resend) ia64_resend_irq(IA64_PERFMON_VECTOR);
 
                pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++;
        }
index 663a186ad194a1abfaa7b00b72a7b93afbcbe107..9065f0f01ba3e7f70b48abf36af96cf46b205514 100644 (file)
@@ -572,7 +572,7 @@ static struct file_operations salinfo_data_fops = {
 };
 
 #ifdef CONFIG_HOTPLUG_CPU
-static int
+static int __devinit
 salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
 {
        unsigned int i, cpu = (unsigned long)hcpu;
@@ -673,9 +673,7 @@ salinfo_init(void)
        salinfo_timer.function = &salinfo_timeout;
        add_timer(&salinfo_timer);
 
-#ifdef CONFIG_HOTPLUG_CPU
-       register_cpu_notifier(&salinfo_cpu_notifier);
-#endif
+       register_hotcpu_notifier(&salinfo_cpu_notifier);
 
        return 0;
 }
index 44e9547878ac7310b6f11502d1a709fd5805bd66..5203df78f150cd1d9cf35c5b888a958f4dd10cdd 100644 (file)
@@ -677,16 +677,16 @@ int migrate_platform_irqs(unsigned int cpu)
                        new_cpei_cpu = any_online_cpu(cpu_online_map);
                        mask = cpumask_of_cpu(new_cpei_cpu);
                        set_cpei_target_cpu(new_cpei_cpu);
-                       desc = irq_descp(ia64_cpe_irq);
+                       desc = irq_desc + ia64_cpe_irq;
                        /*
                         * Switch for now, immediatly, we need to do fake intr
                         * as other interrupts, but need to study CPEI behaviour with
                         * polling before making changes.
                         */
                        if (desc) {
-                               desc->handler->disable(ia64_cpe_irq);
-                               desc->handler->set_affinity(ia64_cpe_irq, mask);
-                               desc->handler->enable(ia64_cpe_irq);
+                               desc->chip->disable(ia64_cpe_irq);
+                               desc->chip->set_affinity(ia64_cpe_irq, mask);
+                               desc->chip->enable(ia64_cpe_irq);
                                printk ("Re-targetting CPEI to cpu %d\n", new_cpei_cpu);
                        }
                }
index 879edb51d1e0e1b2c29698815127dc8b215f7067..5511d9c6c70152fe67b1025c1fe8ea8044926760 100644 (file)
 #include <asm/numa.h>
 #include <asm/cpu.h>
 
-#ifdef CONFIG_NUMA
-static struct node *sysfs_nodes;
-#endif
 static struct ia64_cpu *sysfs_cpus;
 
 int arch_register_cpu(int num)
 {
-       struct node *parent = NULL;
-       
-#ifdef CONFIG_NUMA
-       parent = &sysfs_nodes[cpu_to_node(num)];
-#endif /* CONFIG_NUMA */
-
 #if defined (CONFIG_ACPI) && defined (CONFIG_HOTPLUG_CPU)
        /*
         * If CPEI cannot be re-targetted, and this is
@@ -48,21 +39,14 @@ int arch_register_cpu(int num)
                sysfs_cpus[num].cpu.no_control = 1;
 #endif
 
-       return register_cpu(&sysfs_cpus[num].cpu, num, parent);
+       return register_cpu(&sysfs_cpus[num].cpu, num);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
 
 void arch_unregister_cpu(int num)
 {
-       struct node *parent = NULL;
-
-#ifdef CONFIG_NUMA
-       int node = cpu_to_node(num);
-       parent = &sysfs_nodes[node];
-#endif /* CONFIG_NUMA */
-
-       return unregister_cpu(&sysfs_cpus[num].cpu, parent);
+       return unregister_cpu(&sysfs_cpus[num].cpu);
 }
 EXPORT_SYMBOL(arch_register_cpu);
 EXPORT_SYMBOL(arch_unregister_cpu);
@@ -74,17 +58,11 @@ static int __init topology_init(void)
        int i, err = 0;
 
 #ifdef CONFIG_NUMA
-       sysfs_nodes = kzalloc(sizeof(struct node) * MAX_NUMNODES, GFP_KERNEL);
-       if (!sysfs_nodes) {
-               err = -ENOMEM;
-               goto out;
-       }
-
        /*
         * MCD - Do we want to register all ONLINE nodes, or all POSSIBLE nodes?
         */
        for_each_online_node(i) {
-               if ((err = register_node(&sysfs_nodes[i], i, 0)))
+               if ((err = register_one_node(i)))
                        goto out;
        }
 #endif
@@ -426,7 +404,7 @@ static int __cpuinit cache_remove_dev(struct sys_device * sys_dev)
  * When a cpu is hot-plugged, do a check and initiate
  * cache kobject if necessary
  */
-static int cache_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cache_cpu_callback(struct notifier_block *nfb,
                unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
@@ -444,7 +422,7 @@ static int cache_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cache_cpu_notifier =
+static struct notifier_block __cpuinitdata cache_cpu_notifier =
 {
        .notifier_call = cache_cpu_callback
 };
index b6bcc9fa36030690b073440781e48398847ae547..525b082eb6619821fed5224fccadabaf79002cf4 100644 (file)
@@ -33,7 +33,6 @@
  */
 struct early_node_data {
        struct ia64_node_data *node_data;
-       pg_data_t *pgdat;
        unsigned long pernode_addr;
        unsigned long pernode_size;
        struct bootmem_data bootmem_data;
@@ -46,6 +45,8 @@ struct early_node_data {
 static struct early_node_data mem_data[MAX_NUMNODES] __initdata;
 static nodemask_t memory_less_mask __initdata;
 
+static pg_data_t *pgdat_list[MAX_NUMNODES];
+
 /*
  * To prevent cache aliasing effects, align per-node structures so that they
  * start at addresses that are strided by node number.
@@ -99,7 +100,7 @@ static int __init build_node_maps(unsigned long start, unsigned long len,
  * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
  * called yet.  Note that node 0 will also count all non-existent cpus.
  */
-static int __init early_nr_cpus_node(int node)
+static int __meminit early_nr_cpus_node(int node)
 {
        int cpu, n = 0;
 
@@ -114,7 +115,7 @@ static int __init early_nr_cpus_node(int node)
  * compute_pernodesize - compute size of pernode data
  * @node: the node id.
  */
-static unsigned long __init compute_pernodesize(int node)
+static unsigned long __meminit compute_pernodesize(int node)
 {
        unsigned long pernodesize = 0, cpus;
 
@@ -175,13 +176,13 @@ static void __init fill_pernode(int node, unsigned long pernode,
        pernode += PERCPU_PAGE_SIZE * cpus;
        pernode += node * L1_CACHE_BYTES;
 
-       mem_data[node].pgdat = __va(pernode);
+       pgdat_list[node] = __va(pernode);
        pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
 
        mem_data[node].node_data = __va(pernode);
        pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
 
-       mem_data[node].pgdat->bdata = bdp;
+       pgdat_list[node]->bdata = bdp;
        pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
 
        cpu_data = per_cpu_node_setup(cpu_data, node);
@@ -268,7 +269,7 @@ static int __init find_pernode_space(unsigned long start, unsigned long len,
 static int __init free_node_bootmem(unsigned long start, unsigned long len,
                                    int node)
 {
-       free_bootmem_node(mem_data[node].pgdat, start, len);
+       free_bootmem_node(pgdat_list[node], start, len);
 
        return 0;
 }
@@ -287,7 +288,7 @@ static void __init reserve_pernode_space(void)
        int node;
 
        for_each_online_node(node) {
-               pg_data_t *pdp = mem_data[node].pgdat;
+               pg_data_t *pdp = pgdat_list[node];
 
                if (node_isset(node, memory_less_mask))
                        continue;
@@ -307,6 +308,17 @@ static void __init reserve_pernode_space(void)
        }
 }
 
+static void __meminit scatter_node_data(void)
+{
+       pg_data_t **dst;
+       int node;
+
+       for_each_online_node(node) {
+               dst = LOCAL_DATA_ADDR(pgdat_list[node])->pg_data_ptrs;
+               memcpy(dst, pgdat_list, sizeof(pgdat_list));
+       }
+}
+
 /**
  * initialize_pernode_data - fixup per-cpu & per-node pointers
  *
@@ -317,17 +329,10 @@ static void __init reserve_pernode_space(void)
  */
 static void __init initialize_pernode_data(void)
 {
-       pg_data_t *pgdat_list[MAX_NUMNODES];
        int cpu, node;
 
-       for_each_online_node(node)
-               pgdat_list[node] = mem_data[node].pgdat;
+       scatter_node_data();
 
-       /* Copy the pg_data_t list to each node and init the node field */
-       for_each_online_node(node) {
-               memcpy(mem_data[node].node_data->pg_data_ptrs, pgdat_list,
-                      sizeof(pgdat_list));
-       }
 #ifdef CONFIG_SMP
        /* Set the node_data pointer for each per-cpu struct */
        for (cpu = 0; cpu < NR_CPUS; cpu++) {
@@ -372,7 +377,7 @@ static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize)
        if (bestnode == -1)
                bestnode = anynode;
 
-       ptr = __alloc_bootmem_node(mem_data[bestnode].pgdat, pernodesize,
+       ptr = __alloc_bootmem_node(pgdat_list[bestnode], pernodesize,
                PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
 
        return ptr;
@@ -476,7 +481,7 @@ void __init find_memory(void)
                pernodesize = mem_data[node].pernode_size;
                map = pernode + pernodesize;
 
-               init_bootmem_node(mem_data[node].pgdat,
+               init_bootmem_node(pgdat_list[node],
                                  map>>PAGE_SHIFT,
                                  bdp->node_boot_start>>PAGE_SHIFT,
                                  bdp->node_low_pfn);
@@ -786,3 +791,21 @@ void __init paging_init(void)
 
        zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
 }
+
+pg_data_t *arch_alloc_nodedata(int nid)
+{
+       unsigned long size = compute_pernodesize(nid);
+
+       return kzalloc(size, GFP_KERNEL);
+}
+
+void arch_free_nodedata(pg_data_t *pgdat)
+{
+       kfree(pgdat);
+}
+
+void arch_refresh_nodedata(int update_node, pg_data_t *update_pgdat)
+{
+       pgdat_list[update_node] = update_pgdat;
+       scatter_node_data();
+}
index 11f08001f8c26e9aaa820b37d379d78eedac0bbd..38306e98f04b2877a076ae7ac4912dee3cebfbab 100644 (file)
@@ -652,7 +652,7 @@ void online_page(struct page *page)
        num_physpages++;
 }
 
-int add_memory(u64 start, u64 size)
+int arch_add_memory(int nid, u64 start, u64 size)
 {
        pg_data_t *pgdat;
        struct zone *zone;
@@ -660,7 +660,7 @@ int add_memory(u64 start, u64 size)
        unsigned long nr_pages = size >> PAGE_SHIFT;
        int ret;
 
-       pgdat = NODE_DATA(0);
+       pgdat = NODE_DATA(nid);
 
        zone = pgdat->node_zones + ZONE_NORMAL;
        ret = __add_pages(zone, start_pfn, nr_pages);
@@ -671,7 +671,6 @@ int add_memory(u64 start, u64 size)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(add_memory);
 
 int remove_memory(u64 start, u64 size)
 {
index 77375a55da312fd7b4ac5ddcb68933aadc381e83..5bef0e3603f2a44e19169a5957bb6a0bf201150a 100644 (file)
@@ -568,7 +568,7 @@ pcibios_disable_device (struct pci_dev *dev)
 
 void
 pcibios_align_resource (void *data, struct resource *res,
-                       unsigned long size, unsigned long align)
+                       resource_size_t size, resource_size_t align)
 {
 }
 
index dc8e2b6967135f7d92f7236b9601c09cc349cc14..7bb6ad188ba39855f1516465e4fee89f5b4ef145 100644 (file)
@@ -27,7 +27,7 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info);
 int sn_force_interrupt_flag = 1;
 extern int sn_ioif_inited;
 struct list_head **sn_irq_lh;
-static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */
+static DEFINE_SPINLOCK(sn_irq_info_lock); /* non-IRQ lock */
 
 u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
                                     struct sn_irq_info *sn_irq_info,
@@ -225,8 +225,8 @@ void sn_irq_init(void)
        ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR;
 
        for (i = 0; i < NR_IRQS; i++) {
-               if (base_desc[i].handler == &no_irq_type) {
-                       base_desc[i].handler = &irq_type_sn;
+               if (base_desc[i].chip == &no_irq_type) {
+                       base_desc[i].chip = &irq_type_sn;
                }
        }
 }
index 93577abae36da488e4e7bbe87accbf4436a26f80..3bfccf354343740e3fd811b3ff13d5c1a43a2376 100644 (file)
@@ -458,7 +458,7 @@ void __init sn_setup(char **cmdline_p)
         * support here so we don't have to listen to failed keyboard probe
         * messages.
         */
-       if (version <= 0x0209 && acpi_kbd_controller_present) {
+       if (is_shub1() && version <= 0x0209 && acpi_kbd_controller_present) {
                printk(KERN_INFO "Disabling legacy keyboard support as prom "
                       "is too old and doesn't provide FADT\n");
                acpi_kbd_controller_present = 0;
@@ -577,7 +577,8 @@ void __init sn_cpu_init(void)
        int i;
        static int wars_have_been_checked;
 
-       if (smp_processor_id() == 0 && IS_MEDUSA()) {
+       cpuid = smp_processor_id();
+       if (cpuid == 0 && IS_MEDUSA()) {
                if (ia64_sn_is_fake_prom())
                        sn_prom_type = 2;
                else
@@ -596,6 +597,12 @@ void __init sn_cpu_init(void)
                BUG();
        sn_hub_info->as_shift = sn_hub_info->nasid_shift - 2;
 
+       /*
+        * Don't check status. The SAL call is not supported on all PROMs
+        * but a failure is harmless.
+        */
+       (void) ia64_sn_set_cpu_number(cpuid);
+
        /*
         * The boot cpu makes this call again after platform initialization is
         * complete.
@@ -607,7 +614,6 @@ void __init sn_cpu_init(void)
                if (ia64_sn_get_prom_feature_set(i, &sn_prom_features[i]) != 0)
                        break;
 
-       cpuid = smp_processor_id();
        cpuphyid = get_sapicid();
 
        if (ia64_sn_get_sapic_info(cpuphyid, &nasid, &subnode, &slice))
index 20de72791b979d64791fe119f86153b9d2a93a23..e4aa839d0189f57eaa99d673793b0de1ca3a621e 100644 (file)
@@ -595,7 +595,7 @@ tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
 
        /* sanity check prom rev */
 
-       if (sn_sal_rev() < 0x0406) {
+       if (is_shub1() && sn_sal_rev() < 0x0406) {
                printk
                    (KERN_ERR "%s:  SGI prom rev 4.06 or greater required "
                     "for tioca support\n", __FUNCTION__);
index a4634b06f67554ffeb3f9c84f33bb213ca493b7b..3841861df6a2a0565fc19aad6b59e8a5fa0490ee 100644 (file)
@@ -54,7 +54,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index 3cd3c2988a4875f6da0c8e2fb8af921264beba42..1ff483c8a4c9749c99d8f70b052ee9d805cc3aa6 100644 (file)
@@ -275,7 +275,7 @@ static int __init topology_init(void)
        int i;
 
        for_each_present_cpu(i)
-               register_cpu(&cpu_devices[i], i, NULL);
+               register_cpu(&cpu_devices[i], i);
 
        return 0;
 }
index 6328e1357a80637c324421ffed54af28e223f804..f9f56c2701951c10f0c44883c57a8f89fa3ddf2b 100644 (file)
@@ -87,7 +87,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on M32104UT-LAN (SMC91C111)*/
        irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].handler = &m32104ut_irq_type;
+       irq_desc[M32R_IRQ_INT0].chip = &m32104ut_irq_type;
        irq_desc[M32R_IRQ_INT0].action = 0;
        irq_desc[M32R_IRQ_INT0].depth = 1;
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD11; /* "H" level sense */
@@ -96,7 +96,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &m32104ut_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &m32104ut_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -105,7 +105,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &m32104ut_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &m32104ut_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = M32R_ICUCR_IEN;
@@ -113,7 +113,7 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &m32104ut_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &m32104ut_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = M32R_ICUCR_IEN;
index fad1fc99bb272d8b4d485bc9346de58f027c2468..b6ab00eff58057db820edf51c06cfdc08a4b5017 100644 (file)
@@ -301,7 +301,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/
        irq_desc[M32700UT_LAN_IRQ_LAN].status = IRQ_DISABLED;
-       irq_desc[M32700UT_LAN_IRQ_LAN].handler = &m32700ut_lanpld_irq_type;
+       irq_desc[M32700UT_LAN_IRQ_LAN].chip = &m32700ut_lanpld_irq_type;
        irq_desc[M32700UT_LAN_IRQ_LAN].action = 0;
        irq_desc[M32700UT_LAN_IRQ_LAN].depth = 1;       /* disable nested irq */
        lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;   /* "H" edge sense */
@@ -310,7 +310,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -318,7 +318,7 @@ void __init init_IRQ(void)
 
        /* SIO0 : receive */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -326,7 +326,7 @@ void __init init_IRQ(void)
 
        /* SIO0 : send */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
@@ -334,7 +334,7 @@ void __init init_IRQ(void)
 
        /* SIO1 : receive */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -342,7 +342,7 @@ void __init init_IRQ(void)
 
        /* SIO1 : send */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -350,7 +350,7 @@ void __init init_IRQ(void)
 
        /* DMA1 : */
        irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_DMA1].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_DMA1].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_DMA1].action = 0;
        irq_desc[M32R_IRQ_DMA1].depth = 1;
        icu_data[M32R_IRQ_DMA1].icucr = 0;
@@ -359,7 +359,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
        /* INT#1: SIO0 Receive on PLD */
        irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_RCV].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_RCV].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_SIO0_RCV].action = 0;
        irq_desc[PLD_IRQ_SIO0_RCV].depth = 1;   /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
@@ -367,7 +367,7 @@ void __init init_IRQ(void)
 
        /* INT#1: SIO0 Send on PLD */
        irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_SND].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_SND].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_SIO0_SND].action = 0;
        irq_desc[PLD_IRQ_SIO0_SND].depth = 1;   /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
@@ -376,7 +376,7 @@ void __init init_IRQ(void)
 
        /* INT#1: CFC IREQ on PLD */
        irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_CFIREQ].action = 0;
        irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;       /* 'L' level sense */
@@ -384,7 +384,7 @@ void __init init_IRQ(void)
 
        /* INT#1: CFC Insert on PLD */
        irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_INSERT].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
        irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00;   /* 'L' edge sense */
@@ -392,7 +392,7 @@ void __init init_IRQ(void)
 
        /* INT#1: CFC Eject on PLD */
        irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_EJECT].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_EJECT].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
        irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;    /* 'H' edge sense */
@@ -416,7 +416,7 @@ void __init init_IRQ(void)
        outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
 
     irq_desc[M32700UT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED;
-    irq_desc[M32700UT_LCD_IRQ_USB_INT1].handler = &m32700ut_lcdpld_irq_type;
+    irq_desc[M32700UT_LCD_IRQ_USB_INT1].chip = &m32700ut_lcdpld_irq_type;
     irq_desc[M32700UT_LCD_IRQ_USB_INT1].action = 0;
     irq_desc[M32700UT_LCD_IRQ_USB_INT1].depth = 1;
     lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */
@@ -434,7 +434,7 @@ void __init init_IRQ(void)
         * INT3# is used for AR
         */
        irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT3].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_INT3].chip = &m32700ut_irq_type;
        irq_desc[M32R_IRQ_INT3].action = 0;
        irq_desc[M32R_IRQ_INT3].depth = 1;
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
index 00f253209cb36a0fd8db56407ed88c9d75a5cde0..c268044185f543ed4ffd936996fb29e01c6f1e29 100644 (file)
@@ -86,7 +86,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_NE2000
        /* INT0 : LAN controller (RTL8019AS) */
        irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_INT0].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_INT0].action = 0;
        irq_desc[M32R_IRQ_INT0].depth = 1;
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
@@ -95,7 +95,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -104,7 +104,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -112,7 +112,7 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
@@ -120,7 +120,7 @@ void __init init_IRQ(void)
 
        /* SIO1_R : uart receive data */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -128,7 +128,7 @@ void __init init_IRQ(void)
 
        /* SIO1_S : uart send data */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -138,7 +138,7 @@ void __init init_IRQ(void)
 #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;
+       irq_desc[M32R_IRQ_INT1].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_INT1].action = 0;
        irq_desc[M32R_IRQ_INT1].depth = 1;
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
@@ -146,7 +146,7 @@ void __init init_IRQ(void)
 
        /* INT2 : pccard1 interrupt */
        irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT2].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_INT2].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_INT2].action = 0;
        irq_desc[M32R_IRQ_INT2].depth = 1;
        icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
index eebc9d8b4e72be56fc49df85fe84fca54def62ec..bd2327d5cca28a1528a8f0ae1fec9b83231a7fec 100644 (file)
@@ -87,7 +87,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SMC91X)
        /* INT0 : LAN controller (SMC91111) */
        irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_INT0].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_INT0].action = 0;
        irq_desc[M32R_IRQ_INT0].depth = 1;
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
@@ -96,7 +96,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -105,7 +105,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -113,14 +113,14 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi2_irq(M32R_IRQ_SIO0_S);
        /* SIO1_R : uart receive data */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -128,7 +128,7 @@ void __init init_IRQ(void)
 
        /* SIO1_S : uart send data */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -138,7 +138,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_USB)
        /* INT1 : USB Host controller interrupt */
        irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT1].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_INT1].chip = &mappi2_irq_type;
        irq_desc[M32R_IRQ_INT1].action = 0;
        irq_desc[M32R_IRQ_INT1].depth = 1;
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
@@ -147,7 +147,7 @@ void __init init_IRQ(void)
 
        /* ICUCR40: CFC IREQ */
        irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].handler = &mappi2_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].chip = &mappi2_irq_type;
        irq_desc[PLD_IRQ_CFIREQ].action = 0;
        irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
        icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
@@ -156,7 +156,7 @@ void __init init_IRQ(void)
 #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;
+       irq_desc[PLD_IRQ_CFC_INSERT].chip = &mappi2_irq_type;
        irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
        irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
        icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
@@ -164,7 +164,7 @@ void __init init_IRQ(void)
 
        /* ICUCR42: CFC Eject */
        irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_EJECT].handler = &mappi2_irq_type;
+       irq_desc[PLD_IRQ_CFC_EJECT].chip = &mappi2_irq_type;
        irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
        irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
        icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
index d2ff021e2d3dc7d1acf2c7f2be0b77601210b1a4..014b51d17505a3e9fd047f79b82f20508d813d9d 100644 (file)
@@ -87,7 +87,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SMC91X)
        /* INT0 : LAN controller (SMC91111) */
        irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT0].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_INT0].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_INT0].action = 0;
        irq_desc[M32R_IRQ_INT0].depth = 1;
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
@@ -96,7 +96,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -105,7 +105,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -113,14 +113,14 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi3_irq(M32R_IRQ_SIO0_S);
        /* SIO1_R : uart receive data */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -128,7 +128,7 @@ void __init init_IRQ(void)
 
        /* SIO1_S : uart send data */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -138,7 +138,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_USB)
        /* INT1 : USB Host controller interrupt */
        irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT1].handler = &mappi3_irq_type;
+       irq_desc[M32R_IRQ_INT1].chip = &mappi3_irq_type;
        irq_desc[M32R_IRQ_INT1].action = 0;
        irq_desc[M32R_IRQ_INT1].depth = 1;
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
@@ -147,7 +147,7 @@ void __init init_IRQ(void)
 
        /* CFC IREQ */
        irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].handler = &mappi3_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].chip = &mappi3_irq_type;
        irq_desc[PLD_IRQ_CFIREQ].action = 0;
        irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
        icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
@@ -156,7 +156,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_M32R_CFC)
        /* ICUCR41: CFC Insert & eject */
        irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].handler = &mappi3_irq_type;
+       irq_desc[PLD_IRQ_CFC_INSERT].chip = &mappi3_irq_type;
        irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
        irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
        icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
@@ -166,7 +166,7 @@ void __init init_IRQ(void)
 
        /* IDE IREQ */
        irq_desc[PLD_IRQ_IDEIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_IDEIREQ].handler = &mappi3_irq_type;
+       irq_desc[PLD_IRQ_IDEIREQ].chip = &mappi3_irq_type;
        irq_desc[PLD_IRQ_IDEIREQ].action = 0;
        irq_desc[PLD_IRQ_IDEIREQ].depth = 1;    /* disable nested irq */
        icu_data[PLD_IRQ_IDEIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
index 0e9e63538c0f051cd95cedf7659c9e845d5c2cb3..ea64831aef7ad536869cfdd9dccb63c6ca47b3f6 100644 (file)
@@ -85,7 +85,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_NE2000
        /* INT3 : LAN controller (RTL8019AS) */
        irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT3].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_INT3].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_INT3].action = 0;
        irq_desc[M32R_IRQ_INT3].depth = 1;
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
@@ -94,7 +94,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -103,7 +103,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -111,7 +111,7 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
@@ -119,7 +119,7 @@ void __init init_IRQ(void)
 
        /* SIO1_R : uart receive data */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -127,7 +127,7 @@ void __init init_IRQ(void)
 
        /* SIO1_S : uart send data */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &oaks32r_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
index 548e8fc7949b113a39a697f1cce1407b03c938f5..55e8972d455aedd27a132766a3c89ad42f388474 100644 (file)
@@ -302,7 +302,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/
        irq_desc[OPSPUT_LAN_IRQ_LAN].status = IRQ_DISABLED;
-       irq_desc[OPSPUT_LAN_IRQ_LAN].handler = &opsput_lanpld_irq_type;
+       irq_desc[OPSPUT_LAN_IRQ_LAN].chip = &opsput_lanpld_irq_type;
        irq_desc[OPSPUT_LAN_IRQ_LAN].action = 0;
        irq_desc[OPSPUT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */
        lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;     /* "H" edge sense */
@@ -311,7 +311,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -319,7 +319,7 @@ void __init init_IRQ(void)
 
        /* SIO0 : receive */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -327,7 +327,7 @@ void __init init_IRQ(void)
 
        /* SIO0 : send */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
@@ -335,7 +335,7 @@ void __init init_IRQ(void)
 
        /* SIO1 : receive */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -343,7 +343,7 @@ void __init init_IRQ(void)
 
        /* SIO1 : send */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -351,7 +351,7 @@ void __init init_IRQ(void)
 
        /* DMA1 : */
        irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_DMA1].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_DMA1].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_DMA1].action = 0;
        irq_desc[M32R_IRQ_DMA1].depth = 1;
        icu_data[M32R_IRQ_DMA1].icucr = 0;
@@ -360,7 +360,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
        /* INT#1: SIO0 Receive on PLD */
        irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_RCV].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_RCV].chip = &opsput_pld_irq_type;
        irq_desc[PLD_IRQ_SIO0_RCV].action = 0;
        irq_desc[PLD_IRQ_SIO0_RCV].depth = 1;   /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
@@ -368,7 +368,7 @@ void __init init_IRQ(void)
 
        /* INT#1: SIO0 Send on PLD */
        irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SIO0_SND].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_SND].chip = &opsput_pld_irq_type;
        irq_desc[PLD_IRQ_SIO0_SND].action = 0;
        irq_desc[PLD_IRQ_SIO0_SND].depth = 1;   /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
@@ -378,7 +378,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_M32R_CFC)
        /* INT#1: CFC IREQ on PLD */
        irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFIREQ].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].chip = &opsput_pld_irq_type;
        irq_desc[PLD_IRQ_CFIREQ].action = 0;
        irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;       /* 'L' level sense */
@@ -386,7 +386,7 @@ void __init init_IRQ(void)
 
        /* INT#1: CFC Insert on PLD */
        irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_INSERT].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_INSERT].chip = &opsput_pld_irq_type;
        irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
        irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00;   /* 'L' edge sense */
@@ -394,7 +394,7 @@ void __init init_IRQ(void)
 
        /* INT#1: CFC Eject on PLD */
        irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_CFC_EJECT].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_EJECT].chip = &opsput_pld_irq_type;
        irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
        irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;    /* 'H' edge sense */
@@ -420,7 +420,7 @@ void __init init_IRQ(void)
        outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
 
     irq_desc[OPSPUT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED;
-    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].handler = &opsput_lcdpld_irq_type;
+    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].chip = &opsput_lcdpld_irq_type;
     irq_desc[OPSPUT_LCD_IRQ_USB_INT1].action = 0;
     irq_desc[OPSPUT_LCD_IRQ_USB_INT1].depth = 1;
     lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;   /* "L" level sense */
@@ -438,7 +438,7 @@ void __init init_IRQ(void)
         * INT3# is used for AR
         */
        irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_INT3].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_INT3].chip = &opsput_irq_type;
        irq_desc[M32R_IRQ_INT3].action = 0;
        irq_desc[M32R_IRQ_INT3].depth = 1;
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
index 64be659a23e7efca76532e72e84c952ec6bd76a3..7fa12d8f66b47d63d8695422d429cc515a7a1f10 100644 (file)
@@ -158,7 +158,7 @@ void __init init_IRQ(void)
 
        /* MFT2 : system timer */
        irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_MFT2].action = 0;
        irq_desc[M32R_IRQ_MFT2].depth = 1;
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
@@ -167,7 +167,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SERIAL_M32R_SIO)
        /* SIO0_R : uart receive data */
        irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO0_R].action = 0;
        irq_desc[M32R_IRQ_SIO0_R].depth = 1;
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
@@ -175,7 +175,7 @@ void __init init_IRQ(void)
 
        /* SIO0_S : uart send data */
        irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO0_S].action = 0;
        irq_desc[M32R_IRQ_SIO0_S].depth = 1;
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
@@ -183,7 +183,7 @@ void __init init_IRQ(void)
 
        /* SIO1_R : uart receive data */
        irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO1_R].action = 0;
        irq_desc[M32R_IRQ_SIO1_R].depth = 1;
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
@@ -191,7 +191,7 @@ void __init init_IRQ(void)
 
        /* SIO1_S : uart send data */
        irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
-       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_SIO1_S].action = 0;
        irq_desc[M32R_IRQ_SIO1_S].depth = 1;
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
@@ -201,7 +201,7 @@ void __init init_IRQ(void)
        /* INT#67-#71: CFC#0 IREQ on PLD */
        for (i = 0 ; i < CONFIG_CFC_NUM ; i++ ) {
                irq_desc[PLD_IRQ_CF0 + i].status = IRQ_DISABLED;
-               irq_desc[PLD_IRQ_CF0 + i].handler = &m32700ut_pld_irq_type;
+               irq_desc[PLD_IRQ_CF0 + i].chip = &m32700ut_pld_irq_type;
                irq_desc[PLD_IRQ_CF0 + i].action = 0;
                irq_desc[PLD_IRQ_CF0 + i].depth = 1;    /* disable nested irq */
                pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr
@@ -212,7 +212,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
        /* INT#76: 16552D#0 IREQ on PLD */
        irq_desc[PLD_IRQ_UART0].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_UART0].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_UART0].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_UART0].action = 0;
        irq_desc[PLD_IRQ_UART0].depth = 1;      /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr
@@ -221,7 +221,7 @@ void __init init_IRQ(void)
 
        /* INT#77: 16552D#1 IREQ on PLD */
        irq_desc[PLD_IRQ_UART1].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_UART1].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_UART1].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_UART1].action = 0;
        irq_desc[PLD_IRQ_UART1].depth = 1;      /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr
@@ -232,7 +232,7 @@ void __init init_IRQ(void)
 #if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE)
        /* INT#80: AK4524 IREQ on PLD */
        irq_desc[PLD_IRQ_SNDINT].status = IRQ_DISABLED;
-       irq_desc[PLD_IRQ_SNDINT].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_SNDINT].chip = &m32700ut_pld_irq_type;
        irq_desc[PLD_IRQ_SNDINT].action = 0;
        irq_desc[PLD_IRQ_SNDINT].depth = 1;     /* disable nested irq */
        pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr
index 8b6e723eb82bb30371a02aed5508490a74caa9b1..e767f2ddae72a0ca59dabb0e6e16bbfcc8ea11e7 100644 (file)
@@ -540,6 +540,59 @@ config RAM32BIT
 
 endchoice
 
+comment "ROM configuration"
+
+config ROM
+       bool "Specify ROM linker regions"
+       default n
+       help
+         Define a ROM region for the linker script. This creates a kernel
+         that can be stored in flash, with possibly the text, and data
+         regions being copied out to RAM at startup.
+
+config ROMBASE
+       hex "Address of the base of ROM device"
+       default "0"
+       depends on ROM
+       help
+         Define the address that the ROM region starts at. Some platforms
+         use this to set their chip select region accordingly for the boot
+         device.
+
+config ROMVEC
+       hex "Address of the base of the ROM vectors"
+       default "0"
+       depends on ROM
+       help
+         This is almost always the same as the base of the ROM. Since on all
+         68000 type varients the vectors are at the base of the boot device
+         on system startup.
+
+config ROMVECSIZE
+       hex "Size of ROM vector region (in bytes)"
+       default "0x400"
+       depends on ROM
+       help
+         Define the size of the vector region in ROM. For most 68000
+         varients this would be 0x400 bytes in size. Set to 0 if you do
+         not want a vector region at the start of the ROM.
+
+config ROMSTART
+       hex "Address of the base of system image in ROM"
+       default "0x400"
+       depends on ROM
+       help
+         Define the start address of the system image in ROM. Commonly this
+         is strait after the ROM vectors.
+
+config ROMSIZE
+       hex "Size of the ROM device"
+       default "0x100000"
+       depends on ROM
+       help
+         Size of the ROM device. On some platforms this is used to setup
+         the chip select that controls the boot ROM device.
+
 choice
        prompt "Kernel executes from"
        ---help---
index 6f880cbff1c88d00c13723491456027a7e913140..8951793fd8d4aa3446bb60169e23ac807fb40aa0 100644 (file)
@@ -21,6 +21,7 @@ platform-$(CONFIG_M527x)      := 527x
 platform-$(CONFIG_M5272)       := 5272
 platform-$(CONFIG_M528x)       := 528x
 platform-$(CONFIG_M5307)       := 5307
+platform-$(CONFIG_M532x)       := 532x
 platform-$(CONFIG_M5407)       := 5407
 PLATFORM := $(platform-y)
 
@@ -44,6 +45,7 @@ board-$(CONFIG_senTec)                := senTec
 board-$(CONFIG_SNEHA)          := SNEHA
 board-$(CONFIG_M5208EVB)       := M5208EVB
 board-$(CONFIG_MOD5272)                := MOD5272
+board-$(CONFIG_AVNET)           := AVNET
 BOARD := $(board-y)
 
 model-$(CONFIG_RAMKERNEL)      := ram
@@ -65,6 +67,7 @@ cpuclass-$(CONFIG_M527x)      := 5307
 cpuclass-$(CONFIG_M5272)       := 5307
 cpuclass-$(CONFIG_M528x)       := 5307
 cpuclass-$(CONFIG_M5307)       := 5307
+cpuclass-$(CONFIG_M532x)       := 5307
 cpuclass-$(CONFIG_M5407)       := 5307
 cpuclass-$(CONFIG_M68328)      := 68328
 cpuclass-$(CONFIG_M68EZ328)    := 68328
@@ -81,16 +84,17 @@ export PLATFORM BOARD MODEL CPUCLASS
 #
 # Some CFLAG additions based on specific CPU type.
 #
-cflags-$(CONFIG_M5206)         := -m5200 -Wa,-S -Wa,-m5200
-cflags-$(CONFIG_M5206e)                := -m5200 -Wa,-S -Wa,-m5200
-cflags-$(CONFIG_M520x)         := -m5307 -Wa,-S -Wa,-m5307
-cflags-$(CONFIG_M523x)         := -m5307 -Wa,-S -Wa,-m5307
-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_M528x)         := -m5307 -Wa,-S -Wa,-m5307
-cflags-$(CONFIG_M5307)         := -m5307 -Wa,-S -Wa,-m5307
-cflags-$(CONFIG_M5407)         := -m5200 -Wa,-S -Wa,-m5200
+cflags-$(CONFIG_M5206)         := -m5200
+cflags-$(CONFIG_M5206e)                := -m5200
+cflags-$(CONFIG_M520x)         := -m5307
+cflags-$(CONFIG_M523x)         := -m5307
+cflags-$(CONFIG_M5249)         := -m5200
+cflags-$(CONFIG_M527x)         := -m5307
+cflags-$(CONFIG_M5272)         := -m5307
+cflags-$(CONFIG_M528x)         := -m5307
+cflags-$(CONFIG_M5307)         := -m5307
+cflags-$(CONFIG_M532x)         := -m5307
+cflags-$(CONFIG_M5407)         := -m5200
 cflags-$(CONFIG_M68328)                := -m68000
 cflags-$(CONFIG_M68EZ328)      := -m68000
 cflags-$(CONFIG_M68VZ328)      := -m68000
index 2d59ba1a79ba4e984b6a3d1bc3d6d18e648c4c94..3891de09ac2372e1fcd51a11e8ea44a12cfe3262 100644 (file)
@@ -1,21 +1,22 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.13-uc0
-# Wed Aug 31 15:03:26 2005
+# Linux kernel version: 2.6.17
+# Tue Jun 27 12:57:06 2006
 #
-CONFIG_M68KNOMMU=y
+CONFIG_M68K=y
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
-CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_TIME_LOW_RES=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
@@ -23,32 +24,54 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
 # General setup
 #
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=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_HOTPLUG is not set
-# CONFIG_KOBJECT_UEVENT is not set
 # CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
 #
 # CONFIG_MODULES is not set
 
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
 #
 # Processor type and features
 #
@@ -58,6 +81,7 @@ CONFIG_BASE_SMALL=0
 # CONFIG_M68360 is not set
 # CONFIG_M5206 is not set
 # CONFIG_M5206e is not set
+# CONFIG_M520x is not set
 # CONFIG_M523x is not set
 # CONFIG_M5249 is not set
 # CONFIG_M5271 is not set
@@ -65,29 +89,12 @@ CONFIG_M5272=y
 # CONFIG_M5275 is not set
 # CONFIG_M528x is not set
 # CONFIG_M5307 is not set
+# CONFIG_M532x is not set
 # CONFIG_M5407 is not set
 CONFIG_COLDFIRE=y
-# CONFIG_CLOCK_AUTO is not set
-# CONFIG_CLOCK_11MHz is not set
-# CONFIG_CLOCK_16MHz is not set
-# CONFIG_CLOCK_20MHz is not set
-# CONFIG_CLOCK_24MHz is not set
-# CONFIG_CLOCK_25MHz is not set
-# CONFIG_CLOCK_33MHz is not set
-# CONFIG_CLOCK_40MHz is not set
-# CONFIG_CLOCK_45MHz is not set
-# CONFIG_CLOCK_48MHz is not set
-# CONFIG_CLOCK_50MHz is not set
-# CONFIG_CLOCK_54MHz is not set
-# CONFIG_CLOCK_60MHz is not set
-# CONFIG_CLOCK_62_5MHz is not set
-# CONFIG_CLOCK_64MHz 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
+CONFIG_CLOCK_SET=y
+CONFIG_CLOCK_FREQ=66666666
+CONFIG_CLOCK_DIV=1
 
 #
 # Platform
@@ -102,11 +109,14 @@ CONFIG_M5272C3=y
 CONFIG_FREESCALE=y
 # CONFIG_LARGE_ALLOCS is not set
 CONFIG_4KSTACKS=y
-CONFIG_RAMAUTO=y
-# CONFIG_RAM4MB is not set
-# CONFIG_RAM8MB is not set
-# CONFIG_RAM16MB is not set
-# CONFIG_RAM32MB is not set
+
+#
+# RAM configuration
+#
+CONFIG_RAMBASE=0x0
+CONFIG_RAMSIZE=0x800000
+CONFIG_VECTORBASE=0x0
+CONFIG_KERNELBASE=0x20000
 CONFIG_RAMAUTOBIT=y
 # CONFIG_RAM8BIT is not set
 # CONFIG_RAM16BIT is not set
@@ -119,6 +129,8 @@ CONFIG_FLATMEM_MANUAL=y
 # CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -140,6 +152,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_BINFMT_FLAT=y
 # CONFIG_BINFMT_ZFLAT is not set
 # CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
 
 #
@@ -155,6 +168,7 @@ CONFIG_NET=y
 #
 # Networking options
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -171,18 +185,30 @@ CONFIG_IP_FIB_HASH=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
 # CONFIG_INET_TUNNEL is not set
-# CONFIG_IP_TCPDIAG is not set
-# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_INET_DIAG is not set
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_BIC=y
 # CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETFILTER is not set
 
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
 # CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
@@ -195,8 +221,11 @@ CONFIG_TCP_CONG_BIC=y
 # 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
@@ -205,6 +234,7 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
 
 #
 # Device Drivers
@@ -217,6 +247,11 @@ CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
 
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
 #
 # Memory Technology Devices (MTD)
 #
@@ -235,6 +270,7 @@ CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -254,13 +290,13 @@ CONFIG_MTD_CFI_I2=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_UCLINUX=y
-# CONFIG_MTD_SNAPGEARuC is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -269,7 +305,6 @@ CONFIG_MTD_UCLINUX=y
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
 # CONFIG_MTD_BLOCK2MTD is not set
 
 #
@@ -284,6 +319,11 @@ CONFIG_MTD_UCLINUX=y
 #
 # CONFIG_MTD_NAND is not set
 
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
 #
 # Parallel port support
 #
@@ -296,7 +336,6 @@ CONFIG_MTD_UCLINUX=y
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -304,16 +343,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 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 is not set
-# CONFIG_IOSCHED_CFQ is not set
 # CONFIG_ATA_OVER_ETH is not set
 
 #
@@ -324,6 +354,7 @@ CONFIG_IOSCHED_NOOP=y
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
 
 #
@@ -353,14 +384,16 @@ CONFIG_NETDEVICES=y
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NE2000 is not set
-# CONFIG_NET_PCI is not set
 CONFIG_FEC=y
 # CONFIG_FEC2 is not set
 
@@ -392,6 +425,7 @@ CONFIG_PPP=y
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
 # CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
 # CONFIG_PPPOE is not set
 # CONFIG_SLIP is not set
 # CONFIG_SHAPER is not set
@@ -425,8 +459,6 @@ CONFIG_PPP=y
 #
 # CONFIG_VT is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_LEDMAN is not set
-# CONFIG_RESETSWITCH is not set
 
 #
 # Serial drivers
@@ -450,8 +482,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_MCFWATCHDOG is not set
-# CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
@@ -464,14 +494,19 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # TPM devices
 #
-# CONFIG_MCF_QSPI is not set
-# CONFIG_M41T11M6 is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
 
 #
 # I2C support
 #
 # CONFIG_I2C is not set
-# CONFIG_I2C_SENSOR is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
 
 #
 # Dallas's 1-wire bus
@@ -482,6 +517,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Hardware Monitoring support
 #
 # CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
 
 #
 # Misc devices
@@ -491,6 +527,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
 
 #
 # Digital Video Broadcasting Devices
@@ -502,11 +539,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # CONFIG_FB is not set
 
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-
 #
 # Sound
 #
@@ -517,6 +549,11 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # CONFIG_USB_ARCH_HAS_HCD is not set
 # CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
 
 #
 # USB Gadget Support
@@ -528,14 +565,32 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # CONFIG_MMC is not set
 
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
 #
 # InfiniBand support
 #
 
 #
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 #
 
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
 #
 # File systems
 #
@@ -543,15 +598,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP 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_FS_POSIX_ACL is not set
-
-#
-# XFS support
-#
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_INOTIFY is not set
@@ -559,6 +610,7 @@ CONFIG_ROMFS_FS=y
 # CONFIG_DNOTIFY is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -581,6 +633,7 @@ CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -611,6 +664,7 @@ CONFIG_RAMFS=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -627,8 +681,12 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_UNWIND_INFO is not set
 # CONFIG_FULLDEBUG is not set
 # CONFIG_HIGHPROFILE is not set
 # CONFIG_BOOTPARAM is not set
@@ -655,5 +713,6 @@ CONFIG_LOG_BUF_SHIFT=14
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
 # CONFIG_CRC32 is not set
 # CONFIG_LIBCRC32C is not set
index 8670938f1107a5f9c6a03d2e9bce29ca2d53f19e..db7a0c1cebae8dfe88ad393fa47eefc711790fdc 100644 (file)
@@ -357,7 +357,8 @@ void pcibios_fixup_bus(struct pci_bus *b)
 
 /*****************************************************************************/
 
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align)
+void pcibios_align_resource(void *data, struct resource *res,
+                               resource_size_t size, resource_size_t align)
 {
 }
 
index 6a2f0c6932547079639ebf10ff11955660ad5a3e..59ced831b79214358ef5a5bec9d6bb9def55df4d 100644 (file)
@@ -3,63 +3,13 @@
  *
  *     (C) Copyright 2002-2006, 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
- *     work of the linker script is all at the end, and reasonably
- *     strait forward.
+ *     This linker script is equiped to build either ROM loaded or RAM
+ *     run kernels.
  */
 
 #include <linux/config.h>
 #include <asm-generic/vmlinux.lds.h>
 
-/*
- *     Original Palm pilot (same for Xcopilot).
- *     There is really only a rom target for this.
- */
-#ifdef CONFIG_PILOT3
-#define        ROMVEC_START    0x10c00000
-#define        ROMVEC_LENGTH   0x10400
-#define        ROM_START       0x10c10400
-#define        ROM_LENGTH      0xfec00
-#define        ROM_END         0x10d00000
-#define        DATA_ADDR       CONFIG_KERNELBASE
-#endif
-
-/*
- *     Same setup on both the uCsimm and uCdimm.
- */
-#if defined(CONFIG_UCSIMM) || defined(CONFIG_UCDIMM)
-#ifdef CONFIG_RAMKERNEL
-#define        ROMVEC_START    0x10c10000
-#define        ROMVEC_LENGTH   0x400
-#define        ROM_START       0x10c10400
-#define        ROM_LENGTH      0x1efc00
-#define        ROM_END         0x10e00000
-#endif
-#ifdef CONFIG_ROMKERNEL
-#define        ROMVEC_START    0x10c10000
-#define        ROMVEC_LENGTH   0x400
-#define        ROM_START       0x10c10400
-#define        ROM_LENGTH      0x1efc00
-#define        ROM_END         0x10e00000
-#endif
-#ifdef CONFIG_HIMEMKERNEL
-#define        ROMVEC_START    0x00600000
-#define        ROMVEC_LENGTH   0x400
-#define        ROM_START       0x00600400
-#define        ROM_LENGTH      0x1efc00
-#define        ROM_END         0x007f0000
-#endif
-#endif
-
-#ifdef CONFIG_UCQUICC
-#define        ROMVEC_START    0x00000000
-#define        ROMVEC_LENGTH   0x404
-#define        ROM_START       0x00000404
-#define        ROM_LENGTH      0x1ff6fc
-#define        ROM_END         0x00200000
-#endif
-
 #if defined(CONFIG_RAMKERNEL)
 #define        RAM_START       CONFIG_KERNELBASE
 #define        RAM_LENGTH      (CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE)
 #if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
 #define        RAM_START       CONFIG_RAMBASE
 #define        RAM_LENGTH      CONFIG_RAMSIZE
+#define        ROMVEC_START    CONFIG_ROMVEC
+#define        ROMVEC_LENGTH   CONFIG_ROMVECSIZE
+#define        ROM_START       CONFIG_ROMSTART
+#define        ROM_LENGTH      CONFIG_ROMSIZE
 #define        TEXT            rom
 #define        DATA            ram
 #define        INIT            ram
@@ -90,7 +44,6 @@ MEMORY {
 #ifdef ROM_START
        romvec  : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH
        rom     : ORIGIN = ROM_START, LENGTH = ROM_LENGTH
-       erom    : ORIGIN = ROM_END, LENGTH = 0
 #endif
 }
 
@@ -167,13 +120,6 @@ SECTIONS {
                _etext = . ;
        } > TEXT
 
-#ifdef ROM_END
-       . = ROM_END ;
-       .erom : {
-               __rom_end = . ;
-       } > erom
-#endif
-
        .data DATA_ADDR : {
                . = ALIGN(4);
                _sdata = . ;
index 1b3b719e4479d0458b81e55807ff6d47b0d14bc4..5e5435552d5652da8b4e1b0fa6f81c24a9a028b4 100644 (file)
@@ -8,6 +8,7 @@ head-$(CONFIG_DRAGEN2)  = head-de2.o
 
 obj-y                  += entry.o ints.o timers.o
 obj-$(CONFIG_M68328)   += config.o
+obj-$(CONFIG_ROM)      += romvec.o
 
 extra-y                        := head.o
 extra-$(CONFIG_M68328) += bootlogo.rh head.o
index 2b448a297011f43ed1a26924fe22e6ef0eecb9b9..234430b9551c96fef3e32ff370b69a1500c0fda2 100644 (file)
@@ -28,6 +28,8 @@ _ramstart:
 _ramend:
 .long   0
 
+#define        RAMEND  (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+
 #ifdef CONFIG_INIT_LCD
 splash_bits:
 #include "bootlogo.rh"
@@ -48,7 +50,7 @@ _stext:       movew   #0x2700,%sr
        moveb   #0x81,   0xfffffA27     /* LCKCON */
        movew   #0xff00, 0xfffff412     /* LCD pins */
 #endif
-       moveal  #__ramend-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp
+       moveal  #RAMEND-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp
        movew   #32767, %d0  /* PLL settle wait loop */
 1:     subq    #1, %d0
        bne     1b
@@ -73,13 +75,13 @@ _stext:     movew   #0x2700,%sr
        bhi     1b
 
         movel   #_sdata, %d0    
-        movel   %d0,    _rambase        
-        movel   #_ebss,  %d0
-        movel   %d0,    _ramstart
-       movel   #__ramend-CONFIG_MEMORY_RESERVE*0x100000, %d0
-       movel   %d0,    _ramend
-       movel   #__ramvec,      %d0
-       movel   %d0,    _ramvec
+        movel   %d0, _rambase        
+        movel   #_ebss, %d0
+        movel   %d0, _ramstart
+       movel   #RAMEND-CONFIG_MEMORY_RESERVE*0x100000, %d0
+       movel   %d0, _ramend
+       movel   #CONFIG_VECTORBASE,     %d0
+       movel   %d0, _ramvec
        
 /*
  * load the current task pointer and stack
index 7437217813d2cd6099227f78dfe24fbc79b0bff8..2dda7339aae5cf00136df28f0896926144d0674f 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <asm/system.h>
 #include <asm/irq.h>
+#include <asm/irqnode.h>
 #include <asm/traps.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
@@ -82,25 +83,6 @@ unsigned int local_irq_count[NR_CPUS];
 /* irq node variables for the 32 (potential) on chip sources */
 static irq_node_t int_irq_list[NR_IRQS];
 
-#if !defined(CONFIG_DRAGEN2)
-asm (".global _start, __ramend/n/t"
-     ".section .romvec/n"
-     "e_vectors:\n\t"
-     ".long __ramend-4, _start, buserr, trap, trap, trap, trap, trap\n\t"
-     ".long trap, trap, trap, trap, trap, trap, trap, trap\n\t"
-     ".long trap, trap, trap, trap, trap, trap, trap, trap\n\t"
-     ".long trap, trap, trap, trap\n\t"
-     ".long trap, trap, trap, trap\n\t"
-       /*.long inthandler, inthandler, inthandler, inthandler
-       .long inthandler4, inthandler, inthandler, inthandler   */
-       /* TRAP #0-15 */
-     ".long system_call, trap, trap, trap, trap, trap, trap, trap\n\t"
-     ".long trap, trap, trap, trap, trap, trap, trap, trap\n\t"
-     ".long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n\t"
-     ".text\n"
-     "ignore: rte");
-#endif
-
 /*
  * This function should be called during kernel startup to initialize
  * the IRQ handling routines.
diff --git a/arch/m68knommu/platform/68328/romvec.S b/arch/m68knommu/platform/68328/romvec.S
new file mode 100644 (file)
index 0000000..3e7fe1e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * linux/arch/m68knommu/platform/68328/romvec.S
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Copyright 1996 Roman Zippel
+ * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
+ * Copyright 2006 Greg Ungerer <gerg@snapgear.com>
+ */
+
+#include <linux/config.h>
+
+.global _start
+.global _buserr
+.global trap
+.global system_call
+
+.section .romvec
+
+e_vectors:
+.long CONFIG_RAMBASE+CONFIG_RAMSIZE-4, _start, buserr, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+/* TRAP #0-15 */
+.long system_call, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+
index 3db244625f0fc2c59b2d3f931b18a8f49147f34e..69c670dfd62bb99b77c607b85fb2e0ce61a8f024 100644 (file)
@@ -141,13 +141,13 @@ int BSP_set_clock_mmss (unsigned long nowtime)
 void BSP_reset (void)
 {
   local_irq_disable();
-  asm volatile ("
-    moveal #_start, %a0;
-    moveb #0, 0xFFFFF300;
-    moveal 0(%a0), %sp;
-    moveal 4(%a0), %a0;
-    jmp (%a0);
-    ");
+  asm volatile (
+    "moveal #_start, %a0;\n"
+    "moveb #0, 0xFFFFF300;\n"
+    "moveal 0(%a0), %sp;\n"
+    "moveal 4(%a0), %a0;\n"
+    "jmp (%a0);\n"
+    );
 }
 
 unsigned char *scc1_hwaddr;
index a5c639a51eefd2a5a11ae0b13cc6f040e8d836e8..f497713a4ec7ea72dfbc2a1fc4736c66000d233a 100644 (file)
@@ -18,7 +18,6 @@
 .global _start
 
 .global _rambase
-.global __ramvec
 .global _ramvec
 .global _ramstart
 .global _ramend
@@ -26,6 +25,8 @@
 .global _quicc_base
 .global _periph_base
 
+#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+
 #define REGB                        0x1000
 #define PEPAR                       (_dprbase + REGB + 0x0016)
 #define GMR                         (_dprbase + REGB + 0x0040)
@@ -103,7 +104,7 @@ _stext:
        nop
        ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
        /* We should not need to setup the boot stack the reset should do it. */
-       movea.l #__ramend, %sp                  /*set up stack at the end of DRAM:*/
+       movea.l #RAMEND, %sp                    /*set up stack at the end of DRAM:*/
 
 set_mbar_register:
        moveq.l #0x07, %d1                      /* Setup MBAR */
@@ -163,7 +164,7 @@ configure_memory_controller:
        move.l  %d0, GMR
 
 configure_chip_select_0:
-       move.l  #__ramend, %d0
+       move.l  #RAMEND, %d0
        subi.l  #__ramstart, %d0
        subq.l  #0x01, %d0
        eori.l  #SIM_OR_MASK, %d0
@@ -234,16 +235,10 @@ store_ram_size:
        /* Set ram size information */
        move.l  #_sdata, _rambase
        move.l  #_ebss, _ramstart
-       move.l  #__ramend, %d0
+       move.l  #RAMEND, %d0
        sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
-       move.l  %d0, _ramend                    /* Different from __ramend.*/
+       move.l  %d0, _ramend                    /* Different from RAMEND.*/
 
-store_flash_size:
-       /* Set rom size information */
-       move.l  #__rom_end, %d0
-       sub.l   #__rom_start, %d0
-       move.l  %d0, rom_length
-    
        pea     0
        pea     env
        pea     %sp@(4)
@@ -286,7 +281,7 @@ _dprbase:
      */
  
 .section ".data.initvect","awx"
-    .long   __ramend   /* Reset: Initial Stack Pointer                 - 0.  */
+    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
     .long   _start      /* Reset: Initial Program Counter               - 1.  */
     .long   buserr      /* Bus Error                                    - 2.  */
     .long   trap        /* Address Error                                - 3.  */
index 0da357a4cfee407d141321af4837bbdb5e77f67f..2d28c3e19a881894d2f2389f0691db2364b06f29 100644 (file)
@@ -18,7 +18,6 @@
 .global _start
 
 .global _rambase
-.global __ramvec
 .global _ramvec
 .global _ramstart
 .global _ramend
@@ -26,6 +25,8 @@
 .global _quicc_base
 .global _periph_base
 
+#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+
 #define REGB                        0x1000
 #define PEPAR                       (_dprbase + REGB + 0x0016)
 #define GMR                         (_dprbase + REGB + 0x0040)
@@ -115,7 +116,7 @@ _stext:
        nop
        ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
        /* We should not need to setup the boot stack the reset should do it. */
-       movea.l #__ramend, %sp          /* set up stack at the end of DRAM:*/
+       movea.l #RAMEND, %sp            /* set up stack at the end of DRAM:*/
 
 
 set_mbar_register:
@@ -245,16 +246,10 @@ store_ram_size:
        /* Set ram size information */
        move.l  #_sdata, _rambase
        move.l  #_ebss, _ramstart
-       move.l  #__ramend, %d0
+       move.l  #RAMEND, %d0
        sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
-       move.l  %d0, _ramend                    /* Different from __ramend.*/
+       move.l  %d0, _ramend                    /* Different from RAMEND.*/
 
-store_flash_size:
-       /* Set rom size information */
-       move.l  #__rom_end, %d0
-       sub.l   #__rom_start, %d0
-       move.l  %d0, rom_length
-    
        pea     0
        pea     env
        pea     %sp@(4)
@@ -298,7 +293,7 @@ _dprbase:
      */
  
 .section ".data.initvect","awx"
-    .long   __ramend   /* Reset: Initial Stack Pointer                 - 0.  */
+    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
     .long   _start      /* Reset: Initial Program Counter               - 1.  */
     .long   buserr      /* Bus Error                                    - 2.  */
     .long   trap        /* Address Error                                - 3.  */
index ba184db1651b60daba705d4aaf56315ace42d145..0245fc4a478127223578387c346ff05970e42571 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <asm/system.h>
 #include <asm/irq.h>
+#include <asm/irqnode.h>
 #include <asm/traps.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
index d8d56e5de31073b38e73a5477097d0c20567631d..15a14a67c2bf016ffe2569a9a6505a8b37580d82 100644 (file)
@@ -42,13 +42,13 @@ void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int
 void m68ez328_reset(void)
 {
   local_irq_disable();
-  asm volatile ("
-    moveal #0x10c00000, %a0;
-    moveb #0, 0xFFFFF300;
-    moveal 0(%a0), %sp;
-    moveal 4(%a0), %a0;
-    jmp (%a0);
-    ");
+  asm volatile (
+    "moveal #0x10c00000, %a0;\n"
+    "moveb #0, 0xFFFFF300;\n"
+    "moveal 0(%a0), %sp;\n"
+    "moveal 4(%a0), %a0;\n"
+    "jmp (%a0);\n"
+    );
 }
 
 /***************************************************************************/
index d926524cdf82632e9b456996a61406694fbf3fea..4058de5c8fa2f665cdcd658fcf452c29a98216a4 100644 (file)
@@ -141,13 +141,13 @@ static void init_hardware(char *command, int size)
 static void m68vz328_reset(void)
 {
        local_irq_disable();
-       asm volatile ("
-               moveal #0x10c00000, %a0;
-               moveb #0, 0xFFFFF300;
-               moveal 0(%a0), %sp;
-               moveal 4(%a0), %a0;
-               jmp (%a0);
-       ");
+       asm volatile (
+               "moveal #0x10c00000, %a0;\n\t"
+               "moveb #0, 0xFFFFF300;\n\t"
+               "moveal 0(%a0), %sp;\n\t"
+               "moveal 4(%a0), %a0;\n\t"
+               "jmp (%a0);\n"
+       );
 }
 
 unsigned char *cs8900a_hwaddr;
index 35e038a974c6227940cc4ebe7c5ead85d52e4a65..747a9c1228f247b959bd9ff11cc240c6cd4946ec 100644 (file)
@@ -308,6 +308,7 @@ config MIPS_ATLAS
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SYS_SUPPORTS_MULTITHREADING if EXPERIMENTAL
        help
          This enables support for the MIPS Technologies Atlas evaluation
          board.
@@ -324,6 +325,7 @@ config MIPS_MALTA
        select I8259
        select MIPS_BOARDS_GEN
        select MIPS_BONITO64
+       select MIPS_CPU_SCACHE
        select MIPS_GT64120
        select MIPS_MSC
        select SWAP_IO_SPACE
@@ -336,6 +338,7 @@ config MIPS_MALTA
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SYS_SUPPORTS_MULTITHREADING
        help
          This enables support for the MIPS Technologies Malta evaluation
          board.
@@ -358,7 +361,7 @@ config MIPS_SEAD
          board.
 
 config WR_PPMC
-       bool "Support for Wind River PPMC board"
+       bool "Wind River PPMC board"
        select IRQ_CPU
        select BOOT_ELF32
        select DMA_NONCOHERENT
@@ -536,6 +539,7 @@ config PMC_YOSEMITE
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_HIGHMEM
+       select SYS_SUPPORTS_SMP
        help
          Yosemite is an evaluation board for the RM9000x2 processor
          manufactured by PMC-Sierra.
@@ -590,6 +594,7 @@ config SGI_IP22
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
+       select SYS_SUPPORTS_SMP
        help
          This are the SGI Indy, Challenge S and Indigo2, as well as certain
          OEM variants like the Tandem CMN B006S. To compile a Linux kernel
@@ -601,6 +606,7 @@ config SGI_IP27
        select ARC64
        select BOOT_ELF64
        select DMA_IP27
+       select EARLY_PRINTK
        select HW_HAS_PCI
        select PCI_DOMAINS
        select SYS_HAS_CPU_R10000
@@ -1249,7 +1255,7 @@ config CPU_R6000
        select CPU_SUPPORTS_32BIT_KERNEL
        help
          MIPS Technologies R6000 and R6000A series processors.  Note these
-         processors are extremly rare and the support for them is incomplete.
+         processors are extremely rare and the support for them is incomplete.
 
 config CPU_NEVADA
        bool "RM52xx"
@@ -1370,7 +1376,7 @@ config SYS_HAS_CPU_SB1
 endmenu
 
 #
-# These two indicate any levelof the MIPS32 and MIPS64 architecture
+# These two indicate any level of the MIPS32 and MIPS64 architecture
 #
 config CPU_MIPS32
        bool
@@ -1381,7 +1387,7 @@ config CPU_MIPS64
        default y if CPU_MIPS64_R1 || CPU_MIPS64_R2
 
 #
-# These two indicate the revision of the architecture, either 32 bot 64 bit.
+# These two indicate the revision of the architecture, either Release 1 or Release 2
 #
 config CPU_MIPSR1
        bool
@@ -1474,6 +1480,13 @@ config IP22_CPU_SCACHE
        bool
        select BOARD_SCACHE
 
+#
+# Support for a MIPS32 / MIPS64 style S-caches
+#
+config MIPS_CPU_SCACHE
+       bool
+       select BOARD_SCACHE
+
 config R5000_CPU_SCACHE
        bool
        select BOARD_SCACHE
@@ -1493,32 +1506,57 @@ config SIBYTE_DMA_PAGEOPS
 config CPU_HAS_PREFETCH
        bool
 
-config MIPS_MT
-       bool "Enable MIPS MT"
-
 choice
        prompt "MIPS MT options"
-       depends on MIPS_MT
+
+config MIPS_MT_DISABLED
+       bool "Disable multithreading support."
+       help
+         Use this option if your workload can't take advantage of
+         MIPS hardware multithreading support.  On systems that don't have
+         the option of an MT-enabled processor this option will be the only
+         option in this menu.
 
 config MIPS_MT_SMTC
        bool "SMTC: Use all TCs on all VPEs for SMP"
+       depends on CPU_MIPS32_R2
+       #depends on CPU_MIPS64_R2               # once there is hardware ...
+       depends on SYS_SUPPORTS_MULTITHREADING
        select CPU_MIPSR2_IRQ_VI
        select CPU_MIPSR2_SRS
+       select MIPS_MT
        select SMP
+       help
+         This is a kernel model which is known a SMTC or lately has been
+         marketesed into SMVP.
 
 config MIPS_MT_SMP
        bool "Use 1 TC on each available VPE for SMP"
+       depends on SYS_SUPPORTS_MULTITHREADING
+       select CPU_MIPSR2_IRQ_VI
+       select CPU_MIPSR2_SRS
+       select MIPS_MT
        select SMP
+       help
+         This is a kernel model which is also known a VSMP or lately
+         has been marketesed into SMVP.
 
 config MIPS_VPE_LOADER
        bool "VPE loader support."
-       depends on MIPS_MT
+       depends on SYS_SUPPORTS_MULTITHREADING
+       select MIPS_MT
        help
          Includes a loader for loading an elf relocatable object
          onto another VPE and running it.
 
 endchoice
 
+config MIPS_MT
+       bool
+
+config SYS_SUPPORTS_MULTITHREADING
+       bool
+
 config MIPS_MT_FPAFF
        bool "Dynamic FPU affinity for FP-intensive threads"
        depends on MIPS_MT
@@ -1575,32 +1613,23 @@ config CPU_HAS_LLSC
 config CPU_HAS_WB
        bool
 
+#
+# Vectored interrupt mode is an R2 feature
+#
 config CPU_MIPSR2_IRQ_VI
-       bool "Vectored interrupt mode"
-       depends on CPU_MIPSR2
-       help
-          Vectored interrupt mode allowing faster dispatching of interrupts.
-          The board support code needs to be written to take advantage of this
-          mode.  Compatibility code is included to allow the kernel to run on
-          a CPU that does not support vectored interrupts.  It's safe to
-          say Y here.
+       bool
 
+#
+# Extended interrupt mode is an R2 feature
+#
 config CPU_MIPSR2_IRQ_EI
-       bool "External interrupt controller mode"
-       depends on CPU_MIPSR2
-       help
-          Extended interrupt mode takes advantage of an external interrupt
-          controller to allow fast dispatching from many possible interrupt
-          sources. Say N unless you know that external interrupt support is
-          required.
+       bool
 
+#
+# Shadow registers are an R2 feature
+#
 config CPU_MIPSR2_SRS
-       bool "Make shadow set registers available for interrupt handlers"
-       depends on CPU_MIPSR2_IRQ_VI || CPU_MIPSR2_IRQ_EI
-       help
-          Allow the kernel to use shadow register sets for fast interrupts.
-          Interrupt handlers must be specially written to use shadow sets.
-          Say N unless you know that shadow register set upport is needed.
+       bool
 
 config CPU_HAS_SYNC
        bool
@@ -1618,6 +1647,11 @@ config GENERIC_IRQ_PROBE
        bool
        default y
 
+config IRQ_PER_CPU
+       depends on SMP
+       bool
+       default y
+
 #
 # - Highmem only makes sense for the 32-bit kernel.
 # - The current highmem code will only work properly on physically indexed
@@ -1676,8 +1710,8 @@ source "mm/Kconfig"
 
 config SMP
        bool "Multi-Processing support"
-       depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250 || QEMU) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP || MIPS_MT_SMTC
-       ---help---
+       depends on SYS_SUPPORTS_SMP
+       help
          This enables support for systems with more than one CPU. If you have
          a system with only one CPU, like most personal computers, say N. If
          you have a system with more than one CPU, say Y.
@@ -1696,6 +1730,9 @@ config SMP
 
          If you don't know what to do here, say N.
 
+config SYS_SUPPORTS_SMP
+       bool
+
 config NR_CPUS
        int "Maximum number of CPUs (2-64)"
        range 2 64
index d5930148495a8522368ac4ff5d3ab30c3c566ab3..ebbb9adc0e2fb01f8113c762b79c32acb65baffc 100644 (file)
@@ -374,6 +374,7 @@ core-$(CONFIG_PMC_YOSEMITE) += arch/mips/pmc-sierra/yosemite/
 cflags-$(CONFIG_PMC_YOSEMITE)  += -Iinclude/asm-mips/mach-yosemite
 load-$(CONFIG_PMC_YOSEMITE)    += 0xffffffff80100000
 
+#
 # Qemu simulating MIPS32 4Kc
 #
 core-$(CONFIG_QEMU)            += arch/mips/qemu/
index 6ee090bd86c9a78bf215179033f5a195e3542d91..a547e47dd5fd4211c09df5029adde7795be4dafd 100644 (file)
@@ -290,7 +290,7 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
                                /* If kmalloc fails, it is caught below same
                                 * as a channel not available.
                                 */
-                               ctp = kmalloc(sizeof(chan_tab_t), GFP_KERNEL);
+                               ctp = kmalloc(sizeof(chan_tab_t), GFP_ATOMIC);
                                chan_tab_ptr[i] = ctp;
                                break;
                        }
@@ -730,6 +730,8 @@ au1xxx_dbdma_get_dest(u32 chanid, void **buf, int *nbytes)
        return rv;
 }
 
+EXPORT_SYMBOL_GPL(au1xxx_dbdma_get_dest);
+
 void
 au1xxx_dbdma_stop(u32 chanid)
 {
@@ -821,6 +823,8 @@ au1xxx_get_dma_residue(u32 chanid)
        return rv;
 }
 
+EXPORT_SYMBOL_GPL(au1xxx_get_dma_residue);
+
 void
 au1xxx_dbdma_chan_free(u32 chanid)
 {
index afe05ec12c27d31326d73937081eb7e0631d1c33..12d6edee895eff9e6a38012ffad36449710a734c 100644 (file)
@@ -333,31 +333,31 @@ static void setup_local_irq(unsigned int irq_nr, int type, int int_req)
                                au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
                                au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
                                au_writel(1<<(irq_nr-32), IC1_CFG0SET);
-                               irq_desc[irq_nr].handler = &rise_edge_irq_type;
+                               irq_desc[irq_nr].chip = &rise_edge_irq_type;
                                break;
                        case INTC_INT_FALL_EDGE: /* 0:1:0 */
                                au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
                                au_writel(1<<(irq_nr-32), IC1_CFG1SET);
                                au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
-                               irq_desc[irq_nr].handler = &fall_edge_irq_type;
+                               irq_desc[irq_nr].chip = &fall_edge_irq_type;
                                break;
                        case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */
                                au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
                                au_writel(1<<(irq_nr-32), IC1_CFG1SET);
                                au_writel(1<<(irq_nr-32), IC1_CFG0SET);
-                               irq_desc[irq_nr].handler = &either_edge_irq_type;
+                               irq_desc[irq_nr].chip = &either_edge_irq_type;
                                break;
                        case INTC_INT_HIGH_LEVEL: /* 1:0:1 */
                                au_writel(1<<(irq_nr-32), IC1_CFG2SET);
                                au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
                                au_writel(1<<(irq_nr-32), IC1_CFG0SET);
-                               irq_desc[irq_nr].handler = &level_irq_type;
+                               irq_desc[irq_nr].chip = &level_irq_type;
                                break;
                        case INTC_INT_LOW_LEVEL: /* 1:1:0 */
                                au_writel(1<<(irq_nr-32), IC1_CFG2SET);
                                au_writel(1<<(irq_nr-32), IC1_CFG1SET);
                                au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
-                               irq_desc[irq_nr].handler = &level_irq_type;
+                               irq_desc[irq_nr].chip = &level_irq_type;
                                break;
                        case INTC_INT_DISABLED: /* 0:0:0 */
                                au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
@@ -385,31 +385,31 @@ static void setup_local_irq(unsigned int irq_nr, int type, int int_req)
                                au_writel(1<<irq_nr, IC0_CFG2CLR);
                                au_writel(1<<irq_nr, IC0_CFG1CLR);
                                au_writel(1<<irq_nr, IC0_CFG0SET);
-                               irq_desc[irq_nr].handler = &rise_edge_irq_type;
+                               irq_desc[irq_nr].chip = &rise_edge_irq_type;
                                break;
                        case INTC_INT_FALL_EDGE: /* 0:1:0 */
                                au_writel(1<<irq_nr, IC0_CFG2CLR);
                                au_writel(1<<irq_nr, IC0_CFG1SET);
                                au_writel(1<<irq_nr, IC0_CFG0CLR);
-                               irq_desc[irq_nr].handler = &fall_edge_irq_type;
+                               irq_desc[irq_nr].chip = &fall_edge_irq_type;
                                break;
                        case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */
                                au_writel(1<<irq_nr, IC0_CFG2CLR);
                                au_writel(1<<irq_nr, IC0_CFG1SET);
                                au_writel(1<<irq_nr, IC0_CFG0SET);
-                               irq_desc[irq_nr].handler = &either_edge_irq_type;
+                               irq_desc[irq_nr].chip = &either_edge_irq_type;
                                break;
                        case INTC_INT_HIGH_LEVEL: /* 1:0:1 */
                                au_writel(1<<irq_nr, IC0_CFG2SET);
                                au_writel(1<<irq_nr, IC0_CFG1CLR);
                                au_writel(1<<irq_nr, IC0_CFG0SET);
-                               irq_desc[irq_nr].handler = &level_irq_type;
+                               irq_desc[irq_nr].chip = &level_irq_type;
                                break;
                        case INTC_INT_LOW_LEVEL: /* 1:1:0 */
                                au_writel(1<<irq_nr, IC0_CFG2SET);
                                au_writel(1<<irq_nr, IC0_CFG1SET);
                                au_writel(1<<irq_nr, IC0_CFG0CLR);
-                               irq_desc[irq_nr].handler = &level_irq_type;
+                               irq_desc[irq_nr].chip = &level_irq_type;
                                break;
                        case INTC_INT_DISABLED: /* 0:0:0 */
                                au_writel(1<<irq_nr, IC0_CFG0CLR);
@@ -585,13 +585,13 @@ void intc1_req1_irqdispatch(struct pt_regs *regs)
  * au_sleep function in power.c.....maybe I should just pm_register()
  * them instead?
  */
-static uint    sleep_intctl_config0[2];
-static uint    sleep_intctl_config1[2];
-static uint    sleep_intctl_config2[2];
-static uint    sleep_intctl_src[2];
-static uint    sleep_intctl_assign[2];
-static uint    sleep_intctl_wake[2];
-static uint    sleep_intctl_mask[2];
+static unsigned int    sleep_intctl_config0[2];
+static unsigned int    sleep_intctl_config1[2];
+static unsigned int    sleep_intctl_config2[2];
+static unsigned int    sleep_intctl_src[2];
+static unsigned int    sleep_intctl_assign[2];
+static unsigned int    sleep_intctl_wake[2];
+static unsigned int    sleep_intctl_mask[2];
 
 void
 save_au1xxx_intctl(void)
index f4926315fb683feaae38234b06d150c6603946ad..b035513fe30a782bd172d4b494fd69ad1213dc77 100644 (file)
@@ -80,17 +80,17 @@ static DEFINE_SPINLOCK(pm_lock);
  * We only have to save/restore registers that aren't otherwise
  * done as part of a driver pm_* function.
  */
-static uint    sleep_aux_pll_cntrl;
-static uint    sleep_cpu_pll_cntrl;
-static uint    sleep_pin_function;
-static uint    sleep_uart0_inten;
-static uint    sleep_uart0_fifoctl;
-static uint    sleep_uart0_linectl;
-static uint    sleep_uart0_clkdiv;
-static uint    sleep_uart0_enable;
-static uint    sleep_usbhost_enable;
-static uint    sleep_usbdev_enable;
-static uint    sleep_static_memctlr[4][3];
+static unsigned int    sleep_aux_pll_cntrl;
+static unsigned int    sleep_cpu_pll_cntrl;
+static unsigned int    sleep_pin_function;
+static unsigned int    sleep_uart0_inten;
+static unsigned int    sleep_uart0_fifoctl;
+static unsigned int    sleep_uart0_linectl;
+static unsigned int    sleep_uart0_clkdiv;
+static unsigned int    sleep_uart0_enable;
+static unsigned int    sleep_usbhost_enable;
+static unsigned int    sleep_usbdev_enable;
+static unsigned int    sleep_static_memctlr[4][3];
 
 /* Define this to cause the value you write to /proc/sys/pm/sleep to
  * set the TOY timer for the amount of time you want to sleep.
index a4898b1bc66adcf10c8e9746ecec9c1293e61349..83f1b31a0b8e9de6e8aa18270d9a6235e8caf4c8 100644 (file)
@@ -65,9 +65,9 @@ int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
 
        /* We use a0 and a1 to pass initrd start and size.
        */
-       if (((uint) argc > 0) && ((uint)argv > 0)) {
-               my_initrd_start = (uint)argc;
-               my_initrd_size = (uint)argv;
+       if (((unsigned int) argc > 0) && ((uint)argv > 0)) {
+               my_initrd_start = (unsigned int)argc;
+               my_initrd_size = (unsigned int)argv;
        }
 
        /* First argv is ignored.
index bacc0c6bfe675e5f3570371ea4f98a9004664ee7..5dd164fc1889290e243d0855ba1978aecf932dc7 100644 (file)
@@ -172,7 +172,7 @@ void _board_init_irq(void)
 
        for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++)
        {
-               irq_desc[irq_nr].handler = &external_irq_type;
+               irq_desc[irq_nr].chip = &external_irq_type;
                pb1200_disable_irq(irq_nr);
        }
 
index 005b025605e6da5c11d582b257323fb2681facf4..3d7670edd5cd50d996ec469875fa4dec429ab2bc 100644 (file)
@@ -254,7 +254,7 @@ static int __init excite_platform_init(void)
        return 0;
 }
 
-void __init plat_setup(void)
+void __init plat_mem_setup(void)
 {
        volatile u32 * const boot_ocd_base = (u32 *) 0xbf7fc000;
 
index 00c62c1c28a35baafc6201f199c0f6241b4edffd..20c845c84d4b4902ab7415e579855de7880dd24a 100644 (file)
@@ -21,8 +21,6 @@
 const char *get_system_type(void)
 {
        switch (mips_machtype) {
-       case MACH_NEC_DDB5074:          return "NEC DDB Vrc-5074";
-       case MACH_NEC_DDB5476:          return "NEC DDB Vrc-5476";
        case MACH_NEC_DDB5477:          return "NEC DDB Vrc-5477";
        case MACH_NEC_ROCKHOPPER:       return "NEC Rockhopper";
        case MACH_NEC_ROCKHOPPERII:     return "NEC RockhopperII";
index 5fcd5f070cdcf6a52cdf5a9ed52185be36932fbb..63c3d6534b3a108bd8d87d11838d585fea80e790 100644 (file)
@@ -107,7 +107,7 @@ void __init vrc5477_irq_init(u32 irq_base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &vrc5477_irq_controller;
+               irq_desc[i].chip = &vrc5477_irq_controller;
        }
 
        vrc5477_irq_base = irq_base;
index d5bca5d233b6e6b67d32546d7789b9be1052926f..da2dbb42f913fc21bfd7dd0177d5ec393ae5a82c 100644 (file)
@@ -144,13 +144,13 @@ void __init init_ioasic_irqs(int base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &ioasic_irq_type;
+               irq_desc[i].chip = &ioasic_irq_type;
        }
        for (; i < base + IO_IRQ_LINES; i++) {
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &ioasic_dma_irq_type;
+               irq_desc[i].chip = &ioasic_dma_irq_type;
        }
 
        ioasic_irq_base = base;
index 898bed502a348fb3a7572e8bd65d550a20d0f46c..d44c00d9e80fa973f32100d4e8c192d4d53b741c 100644 (file)
@@ -123,7 +123,7 @@ void __init init_kn02_irqs(int base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &kn02_irq_type;
+               irq_desc[i].chip = &kn02_irq_type;
        }
 
        kn02_irq_base = base;
index eba5051015a5b40dda71908b46bf1309fa22a32b..1ef676e22ab48778042e3be9b81722b8faa0a239 100644 (file)
@@ -3,4 +3,3 @@
 #
 
 obj-y                  += time.o
-obj-$(CONFIG_PCI)      += pci.o
diff --git a/arch/mips/gt64120/common/pci.c b/arch/mips/gt64120/common/pci.c
deleted file mode 100644 (file)
index e9e5419..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Galileo Evaluation Boards PCI support.
- *
- * The general-purpose functions to read/write and configure the GT64120A's
- * PCI registers (function names start with pci0 or pci1) are either direct
- * copies of functions written by Galileo Technology, or are modifications
- * of their functions to work with Linux 2.4 vs Linux 2.2.  These functions
- * are Copyright - Galileo Technology.
- *
- * Other functions are derived from other MIPS PCI implementations, or were
- * written by RidgeRun, Inc,  Copyright (C) 2000 RidgeRun, Inc.
- *   glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.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/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <asm/gt64120.h>
-
-#define SELF 0
-
-/*
- * pciXReadConfigReg  - Read from a PCI configuration register
- *                    - Make sure the GT is configured as a master before
- *                      reading from another device on the PCI.
- *                   - The function takes care of Big/Little endian conversion.
- * INPUTS:   regOffset: The register offset as it apears in the GT spec (or PCI
- *                        spec)
- *           pciDevNum: The device number needs to be addressed.
- * RETURNS: data , if the data == 0xffffffff check the master abort bit in the
- *                 cause register to make sure the data is valid
- *
- *  Configuration Address 0xCF8:
- *
- *       31 30    24 23  16 15  11 10     8 7      2  0     <=bit Number
- *  |congif|Reserved|  Bus |Device|Function|Register|00|
- *  |Enable|        |Number|Number| Number | Number |  |    <=field Name
- *
- */
-static unsigned int pci0ReadConfigReg(int offset, struct pci_dev *device)
-{
-       unsigned int DataForRegCf8;
-       unsigned int data;
-
-       DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
-                        (PCI_FUNC(device->devfn) << 8) |
-                        (offset & ~0x3)) | 0x80000000;
-       GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
-
-       /*
-        * The casual observer might wonder why the READ is duplicated here,
-        * rather than immediately following the WRITE, and just have the swap
-        * in the "if".  That's because there is a latency problem with trying
-        * to read immediately after setting up the address register.  The "if"
-        * check gives enough time for the address to stabilize, so the READ
-        * can work.
-        */
-       if (PCI_SLOT(device->devfn) == SELF)    /* This board */
-               return GT_READ(GT_PCI0_CFGDATA_OFS);
-       else            /* PCI is little endian so swap the Data. */
-               return __GT_READ(GT_PCI0_CFGDATA_OFS);
-}
-
-/*
- * pciXWriteConfigReg - Write to a PCI configuration register
- *                    - Make sure the GT is configured as a master before
- *                      writingto another device on the PCI.
- *                    - The function takes care of Big/Little endian conversion.
- * Inputs:   unsigned int regOffset: The register offset as it apears in the
- *           GT spec
- *                   (or any other PCI device spec)
- *           pciDevNum: The device number needs to be addressed.
- *
- *  Configuration Address 0xCF8:
- *
- *       31 30    24 23  16 15  11 10     8 7      2  0     <=bit Number
- *  |congif|Reserved|  Bus |Device|Function|Register|00|
- *  |Enable|        |Number|Number| Number | Number |  |    <=field Name
- *
- */
-static void pci0WriteConfigReg(unsigned int offset,
-                              struct pci_dev *device, unsigned int data)
-{
-       unsigned int DataForRegCf8;
-
-       DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
-                        (PCI_FUNC(device->devfn) << 8) |
-                        (offset & ~0x3)) | 0x80000000;
-       GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
-
-       if (PCI_SLOT(device->devfn) == SELF)    /* This board */
-               GT_WRITE(GT_PCI0_CFGDATA_OFS, data);
-       else                    /* configuration Transaction over the pci. */
-               __GT_WRITE(GT_PCI0_CFGDATA_OFS, data);
-}
-
-extern struct pci_ops gt64120_pci_ops;
-
-void __init pcibios_init(void)
-{
-       u32 tmp;
-       struct pci_dev controller;
-
-       controller.devfn = SELF;
-
-       tmp = GT_READ(GT_PCI0_CMD_OFS);         /* Huh??? -- Ralf  */
-       tmp = GT_READ(GT_PCI0_BARE_OFS);
-
-       /*
-        * You have to enable bus mastering to configure any other
-        * card on the bus.
-        */
-       tmp = pci0ReadConfigReg(PCI_COMMAND, &controller);
-       tmp |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
-       pci0WriteConfigReg(PCI_COMMAND, &controller, tmp);
-
-       /*
-        *  Reset PCI I/O and PCI MEM values to ones supported by EVM.
-        */
-       ioport_resource.start   = GT_PCI_IO_BASE;
-       ioport_resource.end     = GT_PCI_IO_BASE + GT_PCI_IO_SIZE - 1;
-       iomem_resource.start    = GT_PCI_MEM_BASE;
-       iomem_resource.end      = GT_PCI_MEM_BASE + GT_PCI_MEM_SIZE - 1;
-
-       pci_scan_bus(0, &gt64120_pci_ops, NULL);
-}
index 46c468b26b30879c72b82e01e52a271b32e61d2a..f489a8067a93fa46570378fd85a5345beb78226c 100644 (file)
@@ -138,7 +138,7 @@ void __init arch_init_irq(void)
        /*  Let's initialize our IRQ descriptors  */
        for (i = 0; i < NR_IRQS; i++) {
                irq_desc[i].status = 0;
-               irq_desc[i].handler = &no_irq_type;
+               irq_desc[i].chip = &no_irq_type;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 0;
                spin_lock_init(&irq_desc[i].lock);
index 1193a22c469376febb694ae9fe5dbb1cf749331d..9804642ecf8945ed1235c5bdcc08bcb55d18a124 100644 (file)
@@ -164,8 +164,8 @@ void __init plat_mem_setup(void)
        pm_power_off = momenco_ocelot_power_off;
 
        /*
-        * initrd_start = (ulong)ocelot_initrd_start;
-        * initrd_end = (ulong)ocelot_initrd_start + (ulong)ocelot_initrd_size;
+        * initrd_start = (unsigned long)ocelot_initrd_start;
+        * initrd_end = (unsigned long)ocelot_initrd_start + (ulong)ocelot_initrd_size;
         * initrd_below_start_ok = 1;
         */
 
index 72606b9af12a929f892acb7ebff4884c46b3a555..7cf52205511ccad299507a650188fb223fbef919 100644 (file)
@@ -9,6 +9,6 @@
 # Makefile for the Wind River MIPS 4KC PPMC Eval Board
 #
 
-obj-y  += int-handler.o irq.o reset.o setup.o time.o pci.o
+obj-y += irq.o reset.o setup.o time.o pci.o
 
 EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/gt64120/wrppmc/int-handler.S b/arch/mips/gt64120/wrppmc/int-handler.S
deleted file mode 100644 (file)
index edee7b3..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle
- * Copyright (C) Wind River System Inc. Rongkai.Zhan <rongkai.zhan@windriver.com>
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-#include <asm/mach-wrppmc/mach-gt64120.h>
-
-       .align  5
-       .set    noat
-NESTED(handle_IRQ, PT_SIZE, sp)
-       SAVE_ALL
-       CLI                             # Important: mark KERNEL mode !
-       .set    at
-
-       mfc0    t0, CP0_CAUSE           # get pending interrupts
-       mfc0    t1, CP0_STATUS          # get enabled interrupts
-       and     t0, t0, t1              # get allowed interrupts
-       andi    t0, t0, 0xFF00
-       beqz    t0, 1f
-       move    a1, sp                  # Prepare 'struct pt_regs *regs' pointer
-
-       andi    t1, t0, CAUSEF_IP7      # CPU Compare/Count internal timer
-       bnez    t1, handle_cputimer_irq
-       andi    t1, t0, CAUSEF_IP6      # UART 16550 port
-       bnez    t1, handle_uart_irq
-       andi    t1, t0, CAUSEF_IP3      # PCI INT_A
-       bnez    t1, handle_pci_intA_irq
-
-       /* wrong alarm or masked ... */
-1:     j       spurious_interrupt
-       nop
-END(handle_IRQ)
-
-       .align  5
-handle_cputimer_irq:
-       li      a0, WRPPMC_MIPS_TIMER_IRQ
-       jal     do_IRQ
-       j       ret_from_irq
-
-       .align  5
-handle_uart_irq:
-       li      a0, WRPPMC_UART16550_IRQ
-       jal     do_IRQ
-       j       ret_from_irq
-
-       .align  5
-handle_pci_intA_irq:
-       li      a0, WRPPMC_PCI_INTA_IRQ
-       jal     do_IRQ
-       j       ret_from_irq
-
index 8605687e24eda75160c5ee1f329d230fdd00b13f..8d75a43ce877b4fb29c90405567307cba134ea71 100644 (file)
 #include <asm/irq_cpu.h>
 #include <asm/gt64120.h>
 
-extern asmlinkage void handle_IRQ(void);
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+       unsigned int pending = read_c0_status() & read_c0_cause();
+
+       if (pending & STATUSF_IP7)
+               do_IRQ(WRPPMC_MIPS_TIMER_IRQ, regs);    /* CPU Compare/Count internal timer */
+       else if (pending & STATUSF_IP6)
+               do_IRQ(WRPPMC_UART16550_IRQ, regs);     /* UART 16550 port */
+       else if (pending & STATUSF_IP3)
+               do_IRQ(WRPPMC_PCI_INTA_IRQ, regs);      /* PCI INT_A */
+       else
+               spurious_interrupt(regs);
+}
 
 /**
  * Initialize GT64120 Interrupt Controller
@@ -50,12 +62,6 @@ void gt64120_init_pic(void)
 
 void __init arch_init_irq(void)
 {
-       /* enable all CPU interrupt bits. */
-       set_c0_status(ST0_IM);  /* IE bit is still 0 */
-
-       /* Install MIPS Interrupt Trap Vector */
-       set_except_vector(0, handle_IRQ);
-
        /* IRQ 0 - 7 are for MIPS common irq_cpu controller */
        mips_cpu_irq_init(0);
 
index 20c591e49dae38a6ab7bf2d5889a6e159725d321..2db6375ef29e5bd518d1338eee1b14363be609e3 100644 (file)
@@ -125,7 +125,7 @@ static void wrppmc_setup_serial(void)
 }
 #endif
 
-void __init plat_setup(void)
+void __init plat_mem_setup(void)
 {
        extern void wrppmc_time_init(void);
        extern void wrppmc_timer_setup(struct irqaction *);
index 175d22adb450bf61f43d26bd51d59f4f5c09a82a..6c24a82df0ddc0829207a28d81c3a6fe932a3255 100644 (file)
@@ -31,10 +31,6 @@ void __init wrppmc_timer_setup(struct irqaction *irq)
 {
        /* Install ISR for timer interrupt */
        setup_irq(WRPPMC_MIPS_TIMER_IRQ, irq);
-
-       /* to generate the first timer interrupt */
-       write_c0_compare(mips_hpt_frequency/HZ);
-       write_c0_count(0);
 }
 
 /*
index 77be7216bdd091430735ccb89c1e356144a779fd..a6749c56fe38d620ea29ca4546fc6a79baf31470 100644 (file)
@@ -208,10 +208,10 @@ void __init arch_init_irq(void)
 #endif
 
        for (i = 0; i <= IT8172_LAST_IRQ; i++) {
-               irq_desc[i].handler = &it8172_irq_type;
+               irq_desc[i].chip = &it8172_irq_type;
                spin_lock_init(&irq_desc[i].lock);
        }
-       irq_desc[MIPS_CPU_TIMER_IRQ].handler = &cp0_irq_type;
+       irq_desc[MIPS_CPU_TIMER_IRQ].chip = &cp0_irq_type;
        set_c0_status(ALLINTS_NOTIMER);
 }
 
index becc9accd49573e5d24e052a8e3d8e2e40699339..478be9858a1e04117eb3456e2200119a083b9f04 100644 (file)
@@ -73,7 +73,7 @@ void __init init_r4030_ints(void)
                irq_desc[i].status     = IRQ_DISABLED;
                irq_desc[i].action     = 0;
                irq_desc[i].depth      = 1;
-               irq_desc[i].handler    = &r4030_irq_type;
+               irq_desc[i].chip    = &r4030_irq_type;
        }
 
        r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 0);
index 11304d1354f45b0d47afc511e9a7811fa9383ca6..380046ea1db55103f5ddbcc2c23e459b951c04ac 100644 (file)
@@ -435,7 +435,7 @@ void jmr3927_irq_init(u32 irq_base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &jmr3927_irq_controller;
+               irq_desc[i].chip = &jmr3927_irq_controller;
        }
 
        jmr3927_irq_base = irq_base;
index 15f46b4471fd081890c2e1fe3394bf8a321f7e1b..7bdbcd811b57cfea8bed7bd42242ff5c6dfea932 100644 (file)
@@ -260,7 +260,7 @@ static unsigned int apm_poll(struct file *fp, poll_table * wait)
  *   has acknowledge does the actual suspend happen.
  */
 static int
-apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
+apm_ioctl(struct inode * inode, struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct apm_user *as = filp->private_data;
        unsigned long flags;
index 8c2c359a05f413bd089a8eb40cf64781ac8bb89a..e045aba4ebda2268f464eb382ca03dcd40bd24b5 100644 (file)
@@ -597,8 +597,6 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c)
                break;
        case PRID_IMP_25KF:
                c->cputype = CPU_25KF;
-               /* Probe for L2 cache */
-               c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
                break;
        case PRID_IMP_34K:
                c->cputype = CPU_34K;
index a9c6de1b954257e8e30e73518009f7cf3d1444ae..457565162dd56fc85583ea8d9d13315d93c6d430 100644 (file)
@@ -87,7 +87,7 @@ FEXPORT(restore_all)                  # restore full frame
        ori     v1, v0, TCSTATUS_IXMT
        mtc0    v1, CP0_TCSTATUS
        andi    v0, TCSTATUS_IXMT
-       ehb
+       _ehb
        mfc0    t0, CP0_TCCONTEXT
        DMT     9                               # dmt t1
        jal     mips_ihb
@@ -95,7 +95,7 @@ FEXPORT(restore_all)                  # restore full frame
        andi    t3, t0, 0xff00
        or      t2, t2, t3
        mtc0    t2, CP0_STATUS
-       ehb
+       _ehb
        andi    t1, t1, VPECONTROL_TE
        beqz    t1, 1f
        EMT
@@ -105,7 +105,7 @@ FEXPORT(restore_all)                        # restore full frame
        xori    v1, v1, TCSTATUS_IXMT
        or      v1, v0, v1
        mtc0    v1, CP0_TCSTATUS
-       ehb
+       _ehb
        xor     t0, t0, t3
        mtc0    t0, CP0_TCCONTEXT
 #endif /* CONFIG_MIPS_MT_SMTC */
index 5fd7a8af0c6256bc720c7fa232ee14d551be3e63..8760131f89d9c57f572bd138ceb42258248a3914 100644 (file)
                ori     t1, t2, TCSTATUS_IXMT
                mtc0    t1, CP0_TCSTATUS
                andi    t2, t2, TCSTATUS_IXMT
-               ehb
+               _ehb
                DMT     9                               # dmt   t1
                jal     mips_ihb
                nop
                xori    t1, t1, TCSTATUS_IXMT
                or      t1, t1, t2
                mtc0    t1, CP0_TCSTATUS
-               ehb
+               _ehb
 #endif /* CONFIG_MIPS_MT_SMTC */
                LONG_L  v0, GDB_FR_STATUS(sp)
                LONG_L  v1, GDB_FR_EPC(sp)
index ff7af369f2862eedd4e8fbf08eb6eb3adf263010..6888cde560afc1b277c3d5844a3fcdca55c1b1b9 100644 (file)
@@ -214,7 +214,7 @@ NESTED(except_vec_vi_handler, 0, sp)
        mtc0    t0, CP0_TCCONTEXT
        xor     t1, t1, t0
        mtc0    t1, CP0_STATUS
-       ehb
+       _ehb
 #endif /* CONFIG_MIPS_MT_SMTC */
        CLI
        move    a0, sp
index bdf6f6eff721262d1c98a9dc48adba2b569adba9..c018098c9a5600ce721ae000f92ef567e92949ed 100644 (file)
@@ -96,7 +96,7 @@
        /* Clear TKSU, leave IXMT */
        xori    t0, 0x00001800
        mtc0    t0, CP0_TCSTATUS
-       ehb
+       _ehb
        /* We need to leave the global IE bit set, but clear EXL...*/
        mfc0    t0, CP0_STATUS
        or      t0, ST0_CU0 | ST0_EXL | ST0_ERL | \set | \clr
index 0cb8ed5662f3d2cbaa1f0ac6cde7cbfa6f5ff8bb..91ffb1233cad92cda4ce6ad163bc880798f7533a 100644 (file)
@@ -120,7 +120,7 @@ int i8259A_irq_pending(unsigned int irq)
 void make_8259A_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &i8259A_irq_type;
+       irq_desc[irq].chip = &i8259A_irq_type;
        enable_irq(irq);
 }
 
@@ -327,7 +327,7 @@ void __init init_i8259_irqs (void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &i8259A_irq_type;
+               irq_desc[i].chip = &i8259A_irq_type;
        }
 
        setup_irq(2, &irq2);
index 97ebdc754b9e6e8a59a1edf02611819872e606fb..f8cd1ac64d88314785849eec94f3d801b49943d7 100644 (file)
@@ -174,14 +174,14 @@ void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq)
 
                switch (imp->im_type) {
                case MSC01_IRQ_EDGE:
-                       irq_desc[base+n].handler = &msc_edgeirq_type;
+                       irq_desc[base+n].chip = &msc_edgeirq_type;
                        if (cpu_has_veic)
                                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;
+                       irq_desc[base+n].chip = &msc_levelirq_type;
                        if (cpu_has_veic)
                                MSCIC_WRITE(MSC01_IC_SUP+n*8, 0);
                        else
index 0613f1f36b1bb0f9dabb0adfcbfbf98b5d378e3c..f9c763a65547f0cc8760aaa8eaf61d8bdbe7d1b4 100644 (file)
@@ -155,7 +155,7 @@ void __init mv64340_irq_init(unsigned int base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 2;
-               irq_desc[i].handler = &mv64340_irq_type;
+               irq_desc[i].chip = &mv64340_irq_type;
        }
 
        irq_base = base;
index 0b130c5ac5d915d6eee4df811cd4b7a5543b2c50..121da385a94d05216488abe15a20b398521e5ff4 100644 (file)
@@ -91,7 +91,7 @@ void __init rm7k_cpu_irq_init(int base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &rm7k_irq_controller;
+               irq_desc[i].chip = &rm7k_irq_controller;
        }
 
        irq_base = base;
index 9b5f20c32acb97177b946fdb1c1a863c1a03cd1b..25109c103e44dff4ed3216ce45f7f27a39bc1732 100644 (file)
@@ -139,11 +139,11 @@ void __init rm9k_cpu_irq_init(int base)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &rm9k_irq_controller;
+               irq_desc[i].chip = &rm9k_irq_controller;
        }
 
        rm9000_perfcount_irq = base + 1;
-       irq_desc[rm9000_perfcount_irq].handler = &rm9k_perfcounter_irq;
+       irq_desc[rm9000_perfcount_irq].chip = &rm9k_perfcounter_irq;
 
        irq_base = base;
 }
index 3dce742e716fd3df1b36920dc3606d2e91fb056b..5c9dcd5eed59e7cf3459381990e873346d329d5a 100644 (file)
@@ -95,7 +95,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -137,7 +137,7 @@ void __init init_IRQ(void)
                irq_desc[i].status  = IRQ_DISABLED;
                irq_desc[i].action  = NULL;
                irq_desc[i].depth   = 1;
-               irq_desc[i].handler = &no_irq_type;
+               irq_desc[i].chip = &no_irq_type;
                spin_lock_init(&irq_desc[i].lock);
 #ifdef CONFIG_MIPS_MT_SMTC
                irq_hwmask[i] = 0;
index 5db67e31ec1accf28c0150ed43a8d91176a3609a..0e455a8ad860d612fa282a775d962275cc5f589e 100644 (file)
@@ -167,14 +167,14 @@ void __init mips_cpu_irq_init(int irq_base)
                        irq_desc[i].status = IRQ_DISABLED;
                        irq_desc[i].action = NULL;
                        irq_desc[i].depth = 1;
-                       irq_desc[i].handler = &mips_mt_cpu_irq_controller;
+                       irq_desc[i].chip = &mips_mt_cpu_irq_controller;
                }
 
        for (i = irq_base + 2; i < irq_base + 8; i++) {
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &mips_cpu_irq_controller;
+               irq_desc[i].chip = &mips_cpu_irq_controller;
        }
 
        mips_cpu_irq_base = irq_base;
index db94e556fc97939eaad0dbcc540d088145c41fe9..e1b85e6c486a1cd392ba351e6f423325b3593636 100644 (file)
@@ -94,7 +94,7 @@
        ori     t1, t2, TCSTATUS_IXMT
        mtc0    t1, CP0_TCSTATUS
        andi    t2, t2, TCSTATUS_IXMT
-       ehb
+       _ehb
        DMT     8                               # dmt   t0
        move    t1,ra
        jal     mips_ihb
        or      a2, t1
        mtc0    a2, CP0_STATUS
 #ifdef CONFIG_MIPS_MT_SMTC
-       ehb
+       _ehb
        andi    t0, t0, VPECONTROL_TE
        beqz    t0, 1f
        emt
        xori    t1, t1, TCSTATUS_IXMT
        or      t1, t1, t2
        mtc0    t1, CP0_TCSTATUS
-       ehb
+       _ehb
 #endif /* CONFIG_MIPS_MT_SMTC */
        move    v0, a0
        jr      ra
index 2d2fdf77e30857f964fbca3b609dadb0bedbe500..6344be46ca8c297494526c2c6e8fe9d60013388e 100644 (file)
@@ -647,6 +647,7 @@ einval:     li      v0, -EINVAL
        sys     sys_unshare             1
        sys     sys_splice              4
        sys     sys_sync_file_range     7       /* 4305 */
+       sys     sys_tee                 4
        .endm
 
        /* We pre-compute the number of _instruction_ bytes needed to
index 9ba750887377a23ce2ce10b9374862b8e8fc7fe6..12d96c7d0bb22bc4b334fcf0004f87c3163a08d7 100644 (file)
@@ -462,3 +462,4 @@ sys_call_table:
        PTR     sys_unshare
        PTR     sys_splice
        PTR     sys_sync_file_range
+       PTR     sys_tee                         /* 5265 */
index 942aca26f9c422854c58a124abfec6ee2dd514a9..685698554a8acf275e3b368d69b75177684a3a9e 100644 (file)
@@ -388,3 +388,4 @@ EXPORT(sysn32_call_table)
        PTR     sys_unshare
        PTR     sys_splice
        PTR     sys_sync_file_range
+       PTR     sys_tee
index 8efb23a841317a03a385f7ccb2c8d9b47b250475..0e632934cb7679a02806ba13c45c877371b2a0be 100644 (file)
@@ -510,4 +510,5 @@ sys_call_table:
        PTR     sys_unshare
        PTR     sys_splice
        PTR     sys32_sync_file_range           /* 4305 */
+       PTR     sys_tee
        .size   sys_call_table,.-sys_call_table
index bfcec8d9bfe4bb4f202bf61c501f49738e12611c..d3e087115023ad0ef6867b5bd12c504ac3b070c5 100644 (file)
@@ -488,6 +488,9 @@ static inline void resource_init(void)
 {
        int i;
 
+       if (UNCAC_BASE != IO_BASE)
+               return;
+
        code_resource.start = virt_to_phys(&_text);
        code_resource.end = virt_to_phys(&_etext) - 1;
        data_resource.start = virt_to_phys(&_etext);
index 298f82fe8440a43d1a8140ed8a256d44595ed6d8..9096a5ea42298d4f409ce249f7f5e4ec3d9195c8 100644 (file)
@@ -446,7 +446,7 @@ static int __init topology_init(void)
        int ret;
 
        for_each_present_cpu(cpu) {
-               ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL);
+               ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu);
                if (ret)
                        printk(KERN_WARNING "topology_init: register_cpu %d "
                               "failed (%d)\n", cpu, ret);
index c9d65196d91760a0ee1876b93ab7a1f69f6c4f8c..72c6d98f8854283cc2dad1e1dc1ac593fe4edd4c 100644 (file)
@@ -52,12 +52,12 @@ FEXPORT(__smtc_ipi_vector)
        .set    noat
        /* Disable thread scheduling to make Status update atomic */
        DMT     27                                      # dmt   k1
-       ehb
+       _ehb
        /* Set EXL */
        mfc0    k0,CP0_STATUS
        ori     k0,k0,ST0_EXL
        mtc0    k0,CP0_STATUS
-       ehb
+       _ehb
        /* Thread scheduling now inhibited by EXL. Restore TE state. */
        andi    k1,k1,VPECONTROL_TE
        beqz    k1,1f
@@ -82,7 +82,7 @@ FEXPORT(__smtc_ipi_vector)
        li      k1,ST0_CU0
        or      k1,k1,k0
        mtc0    k1,CP0_STATUS
-       ehb
+       _ehb
        get_saved_sp
        /* Interrupting TC will have pre-set values in slots in the new frame */
 2:     subu    k1,k1,PT_SIZE
@@ -90,7 +90,7 @@ FEXPORT(__smtc_ipi_vector)
        lw      k0,PT_TCSTATUS(k1)
        /* Write it to TCStatus to restore CU/KSU/IXMT state */
        mtc0    k0,$2,1
-       ehb
+       _ehb
        lw      k0,PT_EPC(k1)
        mtc0    k0,CP0_EPC
        /* Save all will redundantly recompute the SP, but use it for now */
@@ -116,7 +116,7 @@ LEAF(self_ipi)
        mfc0    t0,CP0_TCSTATUS
        ori     t1,t0,TCSTATUS_IXMT
        mtc0    t1,CP0_TCSTATUS
-       ehb
+       _ehb
        /* We know we're in kernel mode, so prepare stack frame */
        subu    t1,sp,PT_SIZE
        sw      ra,PT_EPC(t1)
index 2e8e52c135e6edc17613f24b4e79f29563ef8519..70cf09afdf565c573d5750f70723deed249d98bd 100644 (file)
@@ -367,7 +367,7 @@ void mipsmt_prepare_cpus(void)
        dvpe();
        dmt();
 
-       freeIPIq.lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&freeIPIq.lock);
 
        /*
         * We probably don't have as many VPEs as we do SMP "CPUs",
@@ -375,7 +375,7 @@ void mipsmt_prepare_cpus(void)
         */
        for (i=0; i<NR_CPUS; i++) {
                IPIQ[i].head = IPIQ[i].tail = NULL;
-               IPIQ[i].lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&IPIQ[i].lock);
                IPIQ[i].depth = 0;
                ipi_timer_latch[i] = 0;
        }
index 5e8a18a8e2bda49d4ac59388d6df985eeafe4b1d..6da8c68e89db23660868563359fe45a6b3e91d10 100644 (file)
@@ -301,7 +301,7 @@ asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
  *
  * This is really horribly ugly.
  */
-asmlinkage int sys_ipc (uint call, int first, int second,
+asmlinkage int sys_ipc (unsigned int call, int first, int second,
                        unsigned long third, void __user *ptr, long fifth)
 {
        int version, ret;
@@ -359,18 +359,18 @@ asmlinkage int sys_ipc (uint call, int first, int second,
        case SHMAT:
                switch (version) {
                default: {
-                       ulong raddr;
+                       unsigned long raddr;
                        ret = do_shmat (first, (char __user *) ptr, second,
                                        &raddr);
                        if (ret)
                                return ret;
-                       return put_user (raddr, (ulong __user *) third);
+                       return put_user (raddr, (unsigned long __user *) third);
                }
                case 1: /* iBCS2 emulator entry point */
                        if (!segment_eq(get_fs(), get_ds()))
                                return -EINVAL;
                        return do_shmat (first, (char __user *) ptr, second,
-                                        (ulong *) third);
+                                        (unsigned long *) third);
                }
        case SHMDT:
                return sys_shmdt ((char __user *)ptr);
index ad16eceb24dd34bba57f2673dc2fa31ace1cd8fc..67971938a2cb4f575321a550ff5aee5deacd315f 100644 (file)
@@ -1050,7 +1050,7 @@ void *set_except_vector(int n, void *addr)
        return (void *)old_handler;
 }
 
-#ifdef CONFIG_CPU_MIPSR2
+#ifdef CONFIG_CPU_MIPSR2_SRS
 /*
  * MIPSR2 shadow register set allocation
  * FIXME: SMP...
@@ -1069,11 +1069,9 @@ static struct shadow_registers {
 
 static void mips_srs_init(void)
 {
-#ifdef CONFIG_CPU_MIPSR2_SRS
        shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
        printk(KERN_INFO "%d MIPSR2 register sets available\n",
               shadow_registers.sr_supported);
-#endif
        shadow_registers.sr_allocated = 1;      /* Set 0 used by kernel */
 }
 
@@ -1198,7 +1196,14 @@ void *set_vi_handler(int n, void *addr)
 {
        return set_vi_srs_handler(n, addr, 0);
 }
-#endif
+
+#else
+
+static inline void mips_srs_init(void)
+{
+}
+
+#endif /* CONFIG_CPU_MIPSR2_SRS */
 
 /*
  * This is used by native signal handling
@@ -1388,9 +1393,7 @@ void __init trap_init(void)
        else
                ebase = CAC_BASE;
 
-#ifdef CONFIG_CPU_MIPSR2
        mips_srs_init();
-#endif
 
        per_cpu_trap_init();
 
index 2d3472b21ebbe3ad62b98ff3046380b0039107a3..9316a024a8188ed8d2e92d5db266263b08e2b47a 100644 (file)
@@ -156,6 +156,6 @@ void __init arch_init_irq(void)
                irq_desc[i].status      = IRQ_DISABLED;
                irq_desc[i].action      = 0;
                irq_desc[i].depth       = 1;
-               irq_desc[i].handler     = &lasat_irq_type;
+               irq_desc[i].chip        = &lasat_irq_type;
        }
 }
index db53950b7cfbae7bd9e8936ede6fd6f6f5c64882..9dd6b89255818ddbf22fbcc86e4f294b834c1499 100644 (file)
@@ -215,7 +215,7 @@ void __init arch_init_irq(void)
                irq_desc[i].status      = IRQ_DISABLED;
                irq_desc[i].action      = 0;
                irq_desc[i].depth       = 1;
-               irq_desc[i].handler     = &atlas_irq_type;
+               irq_desc[i].chip        = &atlas_irq_type;
                spin_lock_init(&irq_desc[i].lock);
        }
 }
index 4a6220116c96423ea7f572244a474f6d2c0319da..19e41fd186c4e0c8a9d4ab3646c5897aa359514b 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_CPU_VR41XX)      += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
 obj-$(CONFIG_IP22_CPU_SCACHE)  += sc-ip22.o
 obj-$(CONFIG_R5000_CPU_SCACHE)  += sc-r5k.o
 obj-$(CONFIG_RM7000_CPU_SCACHE)        += sc-rm7k.o
+obj-$(CONFIG_MIPS_CPU_SCACHE)  += sc-mips.o
 
 #
 # Choose one DMA coherency model
index 4a43924cd4fccd1f3415a79bc0562d20420632c8..75d887e89739e2a86f086a8ac33ac26537751a05 100644 (file)
@@ -60,13 +60,13 @@ static unsigned long scache_size __read_mostly;
 /*
  * Dummy cache handling routines for machines without boardcaches
  */
-static void no_sc_noop(void) {}
+static void cache_noop(void) {}
 
 static struct bcache_ops no_sc_ops = {
-       .bc_enable = (void *)no_sc_noop,
-       .bc_disable = (void *)no_sc_noop,
-       .bc_wback_inv = (void *)no_sc_noop,
-       .bc_inv = (void *)no_sc_noop
+       .bc_enable = (void *)cache_noop,
+       .bc_disable = (void *)cache_noop,
+       .bc_wback_inv = (void *)cache_noop,
+       .bc_inv = (void *)cache_noop
 };
 
 struct bcache_ops *bcops = &no_sc_ops;
@@ -94,7 +94,9 @@ static inline void r4k_blast_dcache_page_setup(void)
 {
        unsigned long  dc_lsize = cpu_dcache_line_size();
 
-       if (dc_lsize == 16)
+       if (dc_lsize == 0)
+               r4k_blast_dcache_page = (void *)cache_noop;
+       else if (dc_lsize == 16)
                r4k_blast_dcache_page = blast_dcache16_page;
        else if (dc_lsize == 32)
                r4k_blast_dcache_page = r4k_blast_dcache_page_dc32;
@@ -106,7 +108,9 @@ static inline void r4k_blast_dcache_page_indexed_setup(void)
 {
        unsigned long dc_lsize = cpu_dcache_line_size();
 
-       if (dc_lsize == 16)
+       if (dc_lsize == 0)
+               r4k_blast_dcache_page_indexed = (void *)cache_noop;
+       else if (dc_lsize == 16)
                r4k_blast_dcache_page_indexed = blast_dcache16_page_indexed;
        else if (dc_lsize == 32)
                r4k_blast_dcache_page_indexed = blast_dcache32_page_indexed;
@@ -118,7 +122,9 @@ static inline void r4k_blast_dcache_setup(void)
 {
        unsigned long dc_lsize = cpu_dcache_line_size();
 
-       if (dc_lsize == 16)
+       if (dc_lsize == 0)
+               r4k_blast_dcache = (void *)cache_noop;
+       else if (dc_lsize == 16)
                r4k_blast_dcache = blast_dcache16;
        else if (dc_lsize == 32)
                r4k_blast_dcache = blast_dcache32;
@@ -201,7 +207,9 @@ static inline void r4k_blast_icache_page_setup(void)
 {
        unsigned long ic_lsize = cpu_icache_line_size();
 
-       if (ic_lsize == 16)
+       if (ic_lsize == 0)
+               r4k_blast_icache_page = (void *)cache_noop;
+       else if (ic_lsize == 16)
                r4k_blast_icache_page = blast_icache16_page;
        else if (ic_lsize == 32)
                r4k_blast_icache_page = blast_icache32_page;
@@ -216,7 +224,9 @@ static inline void r4k_blast_icache_page_indexed_setup(void)
 {
        unsigned long ic_lsize = cpu_icache_line_size();
 
-       if (ic_lsize == 16)
+       if (ic_lsize == 0)
+               r4k_blast_icache_page_indexed = (void *)cache_noop;
+       else if (ic_lsize == 16)
                r4k_blast_icache_page_indexed = blast_icache16_page_indexed;
        else if (ic_lsize == 32) {
                if (R4600_V1_INDEX_ICACHEOP_WAR && cpu_is_r4600_v1_x())
@@ -238,7 +248,9 @@ static inline void r4k_blast_icache_setup(void)
 {
        unsigned long ic_lsize = cpu_icache_line_size();
 
-       if (ic_lsize == 16)
+       if (ic_lsize == 0)
+               r4k_blast_icache = (void *)cache_noop;
+       else if (ic_lsize == 16)
                r4k_blast_icache = blast_icache16;
        else if (ic_lsize == 32) {
                if (R4600_V1_INDEX_ICACHEOP_WAR && cpu_is_r4600_v1_x())
@@ -258,7 +270,7 @@ static inline void r4k_blast_scache_page_setup(void)
        unsigned long sc_lsize = cpu_scache_line_size();
 
        if (scache_size == 0)
-               r4k_blast_scache_page = (void *)no_sc_noop;
+               r4k_blast_scache_page = (void *)cache_noop;
        else if (sc_lsize == 16)
                r4k_blast_scache_page = blast_scache16_page;
        else if (sc_lsize == 32)
@@ -276,7 +288,7 @@ static inline void r4k_blast_scache_page_indexed_setup(void)
        unsigned long sc_lsize = cpu_scache_line_size();
 
        if (scache_size == 0)
-               r4k_blast_scache_page_indexed = (void *)no_sc_noop;
+               r4k_blast_scache_page_indexed = (void *)cache_noop;
        else if (sc_lsize == 16)
                r4k_blast_scache_page_indexed = blast_scache16_page_indexed;
        else if (sc_lsize == 32)
@@ -294,7 +306,7 @@ static inline void r4k_blast_scache_setup(void)
        unsigned long sc_lsize = cpu_scache_line_size();
 
        if (scache_size == 0)
-               r4k_blast_scache = (void *)no_sc_noop;
+               r4k_blast_scache = (void *)cache_noop;
        else if (sc_lsize == 16)
                r4k_blast_scache = blast_scache16;
        else if (sc_lsize == 32)
@@ -508,7 +520,7 @@ static inline void local_r4k_flush_icache_range(void *args)
        unsigned long end = fir_args->end;
 
        if (!cpu_has_ic_fills_f_dc) {
-               if (end - start > dcache_size) {
+               if (end - start >= dcache_size) {
                        r4k_blast_dcache();
                } else {
                        R4600_HIT_CACHEOP_WAR_IMPL;
@@ -683,10 +695,12 @@ static void local_r4k_flush_cache_sigtramp(void * arg)
        unsigned long addr = (unsigned long) arg;
 
        R4600_HIT_CACHEOP_WAR_IMPL;
-       protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
+       if (dc_lsize)
+               protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
        if (!cpu_icache_snoops_remote_store && scache_size)
                protected_writeback_scache_line(addr & ~(sc_lsize - 1));
-       protected_flush_icache_line(addr & ~(ic_lsize - 1));
+       if (ic_lsize)
+               protected_flush_icache_line(addr & ~(ic_lsize - 1));
        if (MIPS4K_ICACHE_REFILL_WAR) {
                __asm__ __volatile__ (
                        ".set push\n\t"
@@ -973,8 +987,10 @@ static void __init probe_pcache(void)
        c->icache.waysize = icache_size / c->icache.ways;
        c->dcache.waysize = dcache_size / c->dcache.ways;
 
-       c->icache.sets = icache_size / (c->icache.linesz * c->icache.ways);
-       c->dcache.sets = dcache_size / (c->dcache.linesz * c->dcache.ways);
+       c->icache.sets = c->icache.linesz ?
+               icache_size / (c->icache.linesz * c->icache.ways) : 0;
+       c->dcache.sets = c->dcache.linesz ?
+               dcache_size / (c->dcache.linesz * c->dcache.ways) : 0;
 
        /*
         * R10000 and R12000 P-caches are odd in a positive way.  They're 32kB
@@ -993,10 +1009,16 @@ static void __init probe_pcache(void)
                break;
        case CPU_24K:
        case CPU_34K:
-               if (!(read_c0_config7() & (1 << 16)))
+       case CPU_74K:
+               if ((read_c0_config7() & (1 << 16))) {
+                       /* effectively physically indexed dcache,
+                          thus no virtual aliases. */
+                       c->dcache.flags |= MIPS_CACHE_PINDEX;
+                       break;
+               }
        default:
-                       if (c->dcache.waysize > PAGE_SIZE)
-                               c->dcache.flags |= MIPS_CACHE_ALIASES;
+               if (c->dcache.waysize > PAGE_SIZE)
+                       c->dcache.flags |= MIPS_CACHE_ALIASES;
        }
 
        switch (c->cputype) {
@@ -1092,6 +1114,7 @@ static int __init probe_scache(void)
 
 extern int r5k_sc_init(void);
 extern int rm7k_sc_init(void);
+extern int mips_sc_init(void);
 
 static void __init setup_scache(void)
 {
@@ -1139,17 +1162,29 @@ static void __init setup_scache(void)
                return;
 
        default:
+               if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
+                   c->isa_level == MIPS_CPU_ISA_M32R2 ||
+                   c->isa_level == MIPS_CPU_ISA_M64R1 ||
+                   c->isa_level == MIPS_CPU_ISA_M64R2) {
+#ifdef CONFIG_MIPS_CPU_SCACHE
+                       if (mips_sc_init ()) {
+                               scache_size = c->scache.ways * c->scache.sets * c->scache.linesz;
+                               printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n",
+                                      scache_size >> 10,
+                                      way_string[c->scache.ways], c->scache.linesz);
+                       }
+#else
+                       if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
+                               panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
+#endif
+                       return;
+               }
                sc_present = 0;
        }
 
        if (!sc_present)
                return;
 
-       if ((c->isa_level == MIPS_CPU_ISA_M32R1 ||
-            c->isa_level == MIPS_CPU_ISA_M64R1) &&
-           !(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
-               panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
-
        /* compute a couple of other cache variables */
        c->scache.waysize = scache_size / c->scache.ways;
 
@@ -1246,10 +1281,12 @@ void __init r4k_cache_init(void)
         * This code supports virtually indexed processors and will be
         * unnecessarily inefficient on physically indexed processors.
         */
-       shm_align_mask = max_t( unsigned long,
-                               c->dcache.sets * c->dcache.linesz - 1,
-                               PAGE_SIZE - 1);
-
+       if (c->dcache.linesz)
+               shm_align_mask = max_t( unsigned long,
+                                       c->dcache.sets * c->dcache.linesz - 1,
+                                       PAGE_SIZE - 1);
+       else
+               shm_align_mask = PAGE_SIZE-1;
        flush_cache_all         = r4k_flush_cache_all;
        __flush_cache_all       = r4k___flush_cache_all;
        flush_cache_mm          = r4k_flush_cache_mm;
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
new file mode 100644 (file)
index 0000000..42b5096
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2006 Chris Dearman (chris@mips.com),
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/mipsregs.h>
+#include <asm/bcache.h>
+#include <asm/cacheops.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+#include <asm/r4kcache.h>
+
+/*
+ * MIPS32/MIPS64 L2 cache handling
+ */
+
+/*
+ * Writeback and invalidate the secondary cache before DMA.
+ */
+static void mips_sc_wback_inv(unsigned long addr, unsigned long size)
+{
+       blast_scache_range(addr, addr + size);
+}
+
+/*
+ * Invalidate the secondary cache before DMA.
+ */
+static void mips_sc_inv(unsigned long addr, unsigned long size)
+{
+       blast_inv_scache_range(addr, addr + size);
+}
+
+static void mips_sc_enable(void)
+{
+       /* L2 cache is permanently enabled */
+}
+
+static void mips_sc_disable(void)
+{
+       /* L2 cache is permanently enabled */
+}
+
+static struct bcache_ops mips_sc_ops = {
+       .bc_enable = mips_sc_enable,
+       .bc_disable = mips_sc_disable,
+       .bc_wback_inv = mips_sc_wback_inv,
+       .bc_inv = mips_sc_inv
+};
+
+static inline int __init mips_sc_probe(void)
+{
+       struct cpuinfo_mips *c = &current_cpu_data;
+       unsigned int config1, config2;
+       unsigned int tmp;
+
+       /* Mark as not present until probe completed */
+       c->scache.flags |= MIPS_CACHE_NOT_PRESENT;
+
+       /* Ignore anything but MIPSxx processors */
+       if (c->isa_level != MIPS_CPU_ISA_M32R1 &&
+           c->isa_level != MIPS_CPU_ISA_M32R2 &&
+           c->isa_level != MIPS_CPU_ISA_M64R1 &&
+           c->isa_level != MIPS_CPU_ISA_M64R2)
+               return 0;
+
+       /* Does this MIPS32/MIPS64 CPU have a config2 register? */
+       config1 = read_c0_config1();
+       if (!(config1 & MIPS_CONF_M))
+               return 0;
+
+       config2 = read_c0_config2();
+       tmp = (config2 >> 4) & 0x0f;
+       if (0 < tmp && tmp <= 7)
+               c->scache.linesz = 2 << tmp;
+       else
+               return 0;
+
+       tmp = (config2 >> 8) & 0x0f;
+       if (0 <= tmp && tmp <= 7)
+               c->scache.sets = 64 << tmp;
+       else
+               return 0;
+
+       tmp = (config2 >> 0) & 0x0f;
+       if (0 <= tmp && tmp <= 7)
+               c->scache.ways = tmp + 1;
+       else
+               return 0;
+
+       c->scache.waysize = c->scache.sets * c->scache.linesz;
+       c->scache.waybit = __ffs(c->scache.waysize);
+
+       c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
+
+       return 1;
+}
+
+int __init mips_sc_init(void)
+{
+       int found = mips_sc_probe ();
+       if (found) {
+               mips_sc_enable();
+               bcops = &mips_sc_ops;
+       }
+       return found;
+}
+
index df1485501ce631ed6ff262b0dbbdb8014919739a..d0419480b097571fc857166cfd7d5d21d8e21d7a 100644 (file)
@@ -370,8 +370,8 @@ void __init plat_mem_setup(void)
        pm_power_off = momenco_jaguar_power_off;
 
        /*
-        * initrd_start = (ulong)jaguar_initrd_start;
-        * initrd_end = (ulong)jaguar_initrd_start + (ulong)jaguar_initrd_size;
+        * initrd_start = (unsigned long)jaguar_initrd_start;
+        * initrd_end = (unsigned long)jaguar_initrd_start + (ulong)jaguar_initrd_size;
         * initrd_below_start_ok = 1;
         */
 
index bd885785e2f992f6dd2d80295e5afa427c67551e..31d179c4673fe55cf9c812bcd813963b547a8fa1 100644 (file)
@@ -147,6 +147,6 @@ void cpci_irq_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 2;
-               irq_desc[i].handler = &cpci_irq_type;
+               irq_desc[i].chip = &cpci_irq_type;
        }
 }
index 257e1d1b72ddf1006a8cd31292f774bf47d13b48..a0ee006d75cfbb3e09acbbcf88341e2493ef1a9b 100644 (file)
@@ -242,8 +242,8 @@ void __init plat_mem_setup(void)
        pm_power_off = momenco_ocelot_power_off;
 
        /*
-        * initrd_start = (ulong)ocelot_initrd_start;
-        * initrd_end = (ulong)ocelot_initrd_start + (ulong)ocelot_initrd_size;
+        * initrd_start = (unsigned long)ocelot_initrd_start;
+        * initrd_end = (unsigned long)ocelot_initrd_start + (ulong)ocelot_initrd_size;
         * initrd_below_start_ok = 1;
         */
 
index 755bde5146be1d5d0b77bb319e91be12ecb8923d..852265026fd1f5b830e3e172268c1b7a7425ab35 100644 (file)
@@ -137,10 +137,10 @@ void uart_irq_init(void)
        irq_desc[80].status = IRQ_DISABLED;
        irq_desc[80].action = 0;
        irq_desc[80].depth = 2;
-       irq_desc[80].handler = &uart_irq_type;
+       irq_desc[80].chip = &uart_irq_type;
 
        irq_desc[81].status = IRQ_DISABLED;
        irq_desc[81].action = 0;
        irq_desc[81].depth = 2;
-       irq_desc[81].handler = &uart_irq_type;
+       irq_desc[81].chip = &uart_irq_type;
 }
index 72143ab1e9008c164299a0dd46b2140bb1c10aa0..39da02b4e0761983a3ceeac332a7f6963492ec46 100644 (file)
@@ -174,8 +174,8 @@ void __init plat_mem_setup(void)
        pm_power_off = momenco_ocelot_power_off;
 
        /*
-        * initrd_start = (ulong)ocelot_initrd_start;
-        * initrd_end = (ulong)ocelot_initrd_start + (ulong)ocelot_initrd_size;
+        * initrd_start = (unsigned long)ocelot_initrd_start;
+        * initrd_end = (unsigned long)ocelot_initrd_start + (ulong)ocelot_initrd_size;
         * initrd_below_start_ok = 1;
         */
 
index f26a00e13204dd62b6848120f14a6d46af00b39e..a09c5f901233a3468c85f321250861c9cc275695 100644 (file)
 
 #include "op_impl.h"
 
-#define M_PERFCTL_EXL                  (1UL    <<  0)
-#define M_PERFCTL_KERNEL               (1UL    <<  1)
-#define M_PERFCTL_SUPERVISOR           (1UL    <<  2)
-#define M_PERFCTL_USER                 (1UL    <<  3)
-#define M_PERFCTL_INTERRUPT_ENABLE     (1UL    <<  4)
-#define M_PERFCTL_EVENT(event)         ((event) << 5)
-#define M_PERFCTL_WIDE                 (1UL    << 30)
-#define M_PERFCTL_MORE                 (1UL    << 31)
+#define M_PERFCTL_EXL                  (1UL      <<  0)
+#define M_PERFCTL_KERNEL               (1UL      <<  1)
+#define M_PERFCTL_SUPERVISOR           (1UL      <<  2)
+#define M_PERFCTL_USER                 (1UL      <<  3)
+#define M_PERFCTL_INTERRUPT_ENABLE     (1UL      <<  4)
+#define M_PERFCTL_EVENT(event)         ((event)  << 5)
+#define M_PERFCTL_VPEID(vpe)           ((vpe)    << 16)
+#define M_PERFCTL_MT_EN(filter)                ((filter) << 20)
+#define    M_TC_EN_ALL                 M_PERFCTL_MT_EN(0)
+#define    M_TC_EN_VPE                 M_PERFCTL_MT_EN(1)
+#define    M_TC_EN_TC                  M_PERFCTL_MT_EN(2)
+#define M_PERFCTL_TCID(tcid)           ((tcid)   << 22)
+#define M_PERFCTL_WIDE                 (1UL      << 30)
+#define M_PERFCTL_MORE                 (1UL      << 31)
+
+#define M_COUNTER_OVERFLOW             (1UL      << 31)
+
+#ifdef CONFIG_MIPS_MT_SMP
+#define WHAT   (M_TC_EN_VPE | M_PERFCTL_VPEID(smp_processor_id()))
+#else
+#define WHAT   0
+#endif
 
-#define M_COUNTER_OVERFLOW             (1UL    << 31)
+#define __define_perf_accessors(r, n, np)                              \
+                                                                       \
+static inline unsigned int r_c0_ ## r ## n(void)                       \
+{                                                                      \
+       unsigned int cpu = smp_processor_id();                          \
+                                                                       \
+       switch (cpu) {                                                  \
+       case 0:                                                         \
+               return read_c0_ ## r ## n();                            \
+       case 1:                                                         \
+               return read_c0_ ## r ## np();                           \
+       default:                                                        \
+               BUG();                                                  \
+       }                                                               \
+}                                                                      \
+                                                                       \
+static inline void w_c0_ ## r ## n(unsigned int value)                 \
+{                                                                      \
+       unsigned int cpu = smp_processor_id();                          \
+                                                                       \
+       switch (cpu) {                                                  \
+       case 0:                                                         \
+               write_c0_ ## r ## n(value);                             \
+               return;                                                 \
+       case 1:                                                         \
+               write_c0_ ## r ## np(value);                            \
+               return;                                                 \
+       default:                                                        \
+               BUG();                                                  \
+       }                                                               \
+}                                                                      \
+
+__define_perf_accessors(perfcntr, 0, 2)
+__define_perf_accessors(perfcntr, 1, 3)
+__define_perf_accessors(perfcntr, 2, 2)
+__define_perf_accessors(perfcntr, 3, 2)
+
+__define_perf_accessors(perfctrl, 0, 2)
+__define_perf_accessors(perfctrl, 1, 3)
+__define_perf_accessors(perfctrl, 2, 2)
+__define_perf_accessors(perfctrl, 3, 2)
 
 struct op_mips_model op_model_mipsxx_ops;
 
@@ -66,17 +120,17 @@ static void mipsxx_cpu_setup (void *args)
 
        switch (counters) {
        case 4:
-               write_c0_perfctrl3(0);
-               write_c0_perfcntr3(reg.counter[3]);
+               w_c0_perfctrl3(0);
+               w_c0_perfcntr3(reg.counter[3]);
        case 3:
-               write_c0_perfctrl2(0);
-               write_c0_perfcntr2(reg.counter[2]);
+               w_c0_perfctrl2(0);
+               w_c0_perfcntr2(reg.counter[2]);
        case 2:
-               write_c0_perfctrl1(0);
-               write_c0_perfcntr1(reg.counter[1]);
+               w_c0_perfctrl1(0);
+               w_c0_perfcntr1(reg.counter[1]);
        case 1:
-               write_c0_perfctrl0(0);
-               write_c0_perfcntr0(reg.counter[0]);
+               w_c0_perfctrl0(0);
+               w_c0_perfcntr0(reg.counter[0]);
        }
 }
 
@@ -87,13 +141,13 @@ static void mipsxx_cpu_start(void *args)
 
        switch (counters) {
        case 4:
-               write_c0_perfctrl3(reg.control[3]);
+               w_c0_perfctrl3(WHAT | reg.control[3]);
        case 3:
-               write_c0_perfctrl2(reg.control[2]);
+               w_c0_perfctrl2(WHAT | reg.control[2]);
        case 2:
-               write_c0_perfctrl1(reg.control[1]);
+               w_c0_perfctrl1(WHAT | reg.control[1]);
        case 1:
-               write_c0_perfctrl0(reg.control[0]);
+               w_c0_perfctrl0(WHAT | reg.control[0]);
        }
 }
 
@@ -104,13 +158,13 @@ static void mipsxx_cpu_stop(void *args)
 
        switch (counters) {
        case 4:
-               write_c0_perfctrl3(0);
+               w_c0_perfctrl3(0);
        case 3:
-               write_c0_perfctrl2(0);
+               w_c0_perfctrl2(0);
        case 2:
-               write_c0_perfctrl1(0);
+               w_c0_perfctrl1(0);
        case 1:
-               write_c0_perfctrl0(0);
+               w_c0_perfctrl0(0);
        }
 }
 
@@ -124,12 +178,12 @@ static int mipsxx_perfcount_handler(struct pt_regs *regs)
        switch (counters) {
 #define HANDLE_COUNTER(n)                                              \
        case n + 1:                                                     \
-               control = read_c0_perfctrl ## n();                      \
-               counter = read_c0_perfcntr ## n();                      \
+               control = r_c0_perfctrl ## n();                         \
+               counter = r_c0_perfcntr ## n();                         \
                if ((control & M_PERFCTL_INTERRUPT_ENABLE) &&           \
                    (counter & M_COUNTER_OVERFLOW)) {                   \
                        oprofile_add_sample(regs, n);                   \
-                       write_c0_perfcntr ## n(reg.counter[n]);         \
+                       w_c0_perfcntr ## n(reg.counter[n]);             \
                        handled = 1;                                    \
                }
        HANDLE_COUNTER(3)
@@ -143,35 +197,47 @@ static int mipsxx_perfcount_handler(struct pt_regs *regs)
 
 #define M_CONFIG1_PC   (1 << 4)
 
-static inline int n_counters(void)
+static inline int __n_counters(void)
 {
        if (!(read_c0_config1() & M_CONFIG1_PC))
                return 0;
-       if (!(read_c0_perfctrl0() & M_PERFCTL_MORE))
+       if (!(r_c0_perfctrl0() & M_PERFCTL_MORE))
                return 1;
-       if (!(read_c0_perfctrl1() & M_PERFCTL_MORE))
+       if (!(r_c0_perfctrl1() & M_PERFCTL_MORE))
                return 2;
-       if (!(read_c0_perfctrl2() & M_PERFCTL_MORE))
+       if (!(r_c0_perfctrl2() & M_PERFCTL_MORE))
                return 3;
 
        return 4;
 }
 
+static inline int n_counters(void)
+{
+       int counters = __n_counters();
+
+#ifndef CONFIG_SMP
+       if (current_cpu_data.cputype == CPU_34K)
+               return counters >> 1;
+#endif
+
+       return counters;
+}
+
 static inline void reset_counters(int counters)
 {
        switch (counters) {
        case 4:
-               write_c0_perfctrl3(0);
-               write_c0_perfcntr3(0);
+               w_c0_perfctrl3(0);
+               w_c0_perfcntr3(0);
        case 3:
-               write_c0_perfctrl2(0);
-               write_c0_perfcntr2(0);
+               w_c0_perfctrl2(0);
+               w_c0_perfcntr2(0);
        case 2:
-               write_c0_perfctrl1(0);
-               write_c0_perfcntr1(0);
+               w_c0_perfctrl1(0);
+               w_c0_perfcntr1(0);
        case 1:
-               write_c0_perfctrl0(0);
-               write_c0_perfcntr0(0);
+               w_c0_perfctrl0(0);
+               w_c0_perfcntr0(0);
        }
 }
 
@@ -201,7 +267,6 @@ static int __init mipsxx_init(void)
                op_model_mipsxx_ops.cpu_type = "mips/25K";
                break;
 
-#ifndef CONFIG_SMP
        case CPU_34K:
                op_model_mipsxx_ops.cpu_type = "mips/34K";
                break;
@@ -209,7 +274,6 @@ static int __init mipsxx_init(void)
        case CPU_74K:
                op_model_mipsxx_ops.cpu_type = "mips/74K";
                break;
-#endif
 
        case CPU_5KC:
                op_model_mipsxx_ops.cpu_type = "mips/5K";
index 465778c5d816064e127d77164b7eef4a2ec6d769..35d5927706eac8701f6442fe75620fb381445599 100644 (file)
@@ -23,7 +23,7 @@ obj-$(CONFIG_MARKEINS)                += ops-emma2rh.o pci-emma2rh.o fixup-emma2rh.o
 #
 # These are still pretty much in the old state, watch, go blind.
 #
-obj-$(CONFIG_BASLER_EXCITE)    = ops-titan.o pci-excite.o fixup-excite.o
+obj-$(CONFIG_BASLER_EXCITE)    += ops-titan.o pci-excite.o fixup-excite.o
 obj-$(CONFIG_DDB5477)          += fixup-ddb5477.o pci-ddb5477.o ops-ddb5477.o
 obj-$(CONFIG_LASAT)            += pci-lasat.o
 obj-$(CONFIG_MIPS_ATLAS)       += fixup-atlas.o
index 7688b7711329364f48363ea13caaf27d81bcae94..150419c8b41427717afd66328a655783993a3f59 100644 (file)
@@ -119,7 +119,7 @@ static int tx4927_pcibios_read_config(struct pci_bus *bus, unsigned int devfn, i
 
        switch (size) {
        case 1:
-               *val = *(volatile u8 *) ((ulong) & tx4927_pcicptr->
+               *val = *(volatile u8 *) ((unsigned long) & tx4927_pcicptr->
                               g2pcfgdata |
 #ifdef __LITTLE_ENDIAN
                                                (where & 3));
@@ -128,7 +128,7 @@ static int tx4927_pcibios_read_config(struct pci_bus *bus, unsigned int devfn, i
 #endif
                break;
        case 2:
-               *val = *(volatile u16 *) ((ulong) & tx4927_pcicptr->
+               *val = *(volatile u16 *) ((unsigned long) & tx4927_pcicptr->
                                g2pcfgdata |
 #ifdef __LITTLE_ENDIAN
                                                (where & 3));
@@ -168,7 +168,7 @@ static int tx4927_pcibios_write_config(struct pci_bus *bus, unsigned int devfn,
 
        switch (size) {
        case 1:
-                *(volatile u8 *) ((ulong) & tx4927_pcicptr->
+                *(volatile u8 *) ((unsigned long) & tx4927_pcicptr->
                           g2pcfgdata |
 #ifdef __LITTLE_ENDIAN
                                        (where & 3)) = val;
@@ -178,7 +178,7 @@ static int tx4927_pcibios_write_config(struct pci_bus *bus, unsigned int devfn,
                break;
 
        case 2:
-               *(volatile u16 *) ((ulong) & tx4927_pcicptr->
+               *(volatile u16 *) ((unsigned long) & tx4927_pcicptr->
                            g2pcfgdata |
 #ifdef __LITTLE_ENDIAN
                                        (where & 3)) = val;
index 0ff083489efdba7e5537ea4b8ee871a346fba5ff..4450070845153341476cb4a8eb0fa97ff56cc53b 100644 (file)
@@ -106,7 +106,7 @@ static int tx4938_pcibios_read_config(struct pci_bus *bus, unsigned int devfn,
 
        switch (size) {
        case 1:
-               *val = *(volatile u8 *) ((ulong) & tx4938_pcicptr->g2pcfgdata |
+               *val = *(volatile u8 *) ((unsigned long) & tx4938_pcicptr->g2pcfgdata |
 #ifdef __BIG_ENDIAN
                              ((where & 3) ^ 3));
 #else
@@ -114,7 +114,7 @@ static int tx4938_pcibios_read_config(struct pci_bus *bus, unsigned int devfn,
 #endif
                break;
        case 2:
-               *val = *(volatile u16 *) ((ulong) & tx4938_pcicptr->g2pcfgdata |
+               *val = *(volatile u16 *) ((unsigned long) & tx4938_pcicptr->g2pcfgdata |
 #ifdef __BIG_ENDIAN
                                ((where & 3) ^ 2));
 #else
@@ -154,7 +154,7 @@ static int tx4938_pcibios_write_config(struct pci_bus *bus, unsigned int devfn,
 
        switch (size) {
        case 1:
-               *(volatile u8 *) ((ulong) & tx4938_pcicptr->g2pcfgdata |
+               *(volatile u8 *) ((unsigned long) & tx4938_pcicptr->g2pcfgdata |
 #ifdef __BIG_ENDIAN
                          ((where & 3) ^ 3)) = val;
 #else
@@ -162,7 +162,7 @@ static int tx4938_pcibios_write_config(struct pci_bus *bus, unsigned int devfn,
 #endif
                break;
        case 2:
-               *(volatile u16 *) ((ulong) & tx4938_pcicptr->g2pcfgdata |
+               *(volatile u16 *) ((unsigned long) & tx4938_pcicptr->g2pcfgdata |
 #ifdef __BIG_ENDIAN
                        ((where & 0x3) ^ 0x2)) = val;
 #else
index 4dfce154d4af1cb33e7b35410f3a747d34c47555..ba66f8c9bd4eec824b21882d8129d284289cf6dc 100644 (file)
@@ -51,11 +51,11 @@ unsigned long PCIBIOS_MIN_MEM       = 0;
  */
 void
 pcibios_align_resource(void *data, struct resource *res,
-                      unsigned long size, unsigned long align)
+                      resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
        struct pci_controller *hose = dev->sysdata;
-       unsigned long start = res->start;
+       resource_size_t start = res->start;
 
        if (res->flags & IORESOURCE_IO) {
                /* Make sure we start at our min on all hoses */
index 39ee6314f62757279e12118448a04b70713fb2a7..8f18764a235956c6dbb14825b8cabba6daf8dd91 100644 (file)
@@ -236,7 +236,7 @@ void __init arch_init_irq(void)
        int configPR;
 
        for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) {
-               irq_desc[i].handler = &level_irq_type;
+               irq_desc[i].chip = &level_irq_type;
                pnx8550_ack(i); /* mask the irq just in case  */
        }
 
@@ -273,7 +273,7 @@ void __init arch_init_irq(void)
                /* mask/priority is still 0 so we will not get any
                 * interrupts until it is unmasked */
 
-               irq_desc[i].handler = &level_irq_type;
+               irq_desc[i].chip = &level_irq_type;
        }
 
        /* Priority level 0 */
@@ -282,12 +282,12 @@ void __init arch_init_irq(void)
        /* Set int vector table address */
        PNX8550_GIC_VECTOR_0 = PNX8550_GIC_VECTOR_1 = 0;
 
-       irq_desc[MIPS_CPU_GIC_IRQ].handler = &level_irq_type;
+       irq_desc[MIPS_CPU_GIC_IRQ].chip = &level_irq_type;
        setup_irq(MIPS_CPU_GIC_IRQ, &gic_action);
 
        /* init of Timer interrupts */
        for (i = PNX8550_INT_TIMER_MIN; i <= PNX8550_INT_TIMER_MAX; i++) {
-               irq_desc[i].handler = &level_irq_type;
+               irq_desc[i].chip = &level_irq_type;
        }
 
        /* Stop Timer 1-3 */
@@ -295,7 +295,7 @@ void __init arch_init_irq(void)
        configPR |= 0x00000038;
        write_c0_config7(configPR);
 
-       irq_desc[MIPS_CPU_TIMER_IRQ].handler = &level_irq_type;
+       irq_desc[MIPS_CPU_TIMER_IRQ].chip = &level_irq_type;
        setup_irq(MIPS_CPU_TIMER_IRQ, &timer_action);
 }
 
index 54b65a80abf587d30a54d613b1a268f780f38a3c..fb523ebcafa8e8a5e6c8ee753cdbaa8c6a347e57 100644 (file)
@@ -383,12 +383,12 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 
 
 void pcibios_align_resource(void *data, struct resource *res,
-                            unsigned long size, unsigned long align)
+                            resource_size_t size, resource_size_t align)
 {
         struct pci_dev *dev = data;
 
         if (res->flags & IORESOURCE_IO) {
-                unsigned long start = res->start;
+                resource_size_t start = res->start;
 
                 /* We need to avoid collisions with `mirrored' VGA ports
                    and other strange ISA hardware, so we always want the
index b19820110aa3a91c52c9bf1f0157b3979001a315..989167b49ce92e70611940937a10c3a7efff5e28 100644 (file)
@@ -279,9 +279,9 @@ int __init ip22_eisa_init(void)
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
                if (i < (SGINT_EISA + 8))
-                       irq_desc[i].handler = &ip22_eisa1_irq_type;
+                       irq_desc[i].chip = &ip22_eisa1_irq_type;
                else
-                       irq_desc[i].handler = &ip22_eisa2_irq_type;
+                       irq_desc[i].chip = &ip22_eisa2_irq_type;
        }
 
        /* Cannot use request_irq because of kmalloc not being ready at such
index fc6a7e2b189ccd90224c54dbf6ac4ae62ba99b68..18906af6969100e7c51f9b0c9a62a60ad1c3ad3e 100644 (file)
@@ -436,7 +436,7 @@ void __init arch_init_irq(void)
                irq_desc[i].status      = IRQ_DISABLED;
                irq_desc[i].action      = 0;
                irq_desc[i].depth       = 1;
-               irq_desc[i].handler     = handler;
+               irq_desc[i].chip        = handler;
        }
 
        /* vector handler. this register the IRQ as non-sharable */
index f14ef38646d02258cf7997844bb76c60f7c12414..5e960ae9735afcea622e4e848a1a13645cfd329c 100644 (file)
@@ -33,12 +33,13 @@ config MAPPED_KERNEL
        depends on SGI_IP27
        help
          Change the way a Linux kernel is loaded into memory on a MIPS64
-         machine.  This is required in order to support text replication and
+         machine.  This is required in order to support text replication on
          NUMA.  If you need to understand it, read the source code.
 
 config REPLICATE_KTEXT
        bool "Kernel text replication support"
        depends on SGI_IP27
+       select MAPPED_KERNEL
        help
          Say Y here to enable replicating the kernel text across multiple
          nodes in a NUMA cluster.  This trades memory for speed.
index 686ba14e2882495039bc73fc256fa73840f0b2b4..a457263f4391811d102bfa593dcdcf03374b0a57 100644 (file)
@@ -2,11 +2,12 @@
 # Makefile for the IP27 specific kernel interface routines under Linux.
 #
 
-obj-y  := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o \
-          ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o \
-          ip27-timer.o ip27-hubio.o ip27-xtalk.o
+obj-y  := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o ip27-klnuma.o \
+          ip27-memory.o ip27-nmi.o ip27-reset.o ip27-timer.o ip27-hubio.o \
+          ip27-xtalk.o
 
-obj-$(CONFIG_KGDB)     += ip27-dbgio.o
-obj-$(CONFIG_SMP)      += ip27-smp.o
+obj-$(CONFIG_EARLY_PRINTK)     += ip27-console.o
+obj-$(CONFIG_KGDB)             += ip27-dbgio.o
+obj-$(CONFIG_SMP)              += ip27-smp.o
 
 EXTRA_AFLAGS := $(CFLAGS)
index 3e1ac299b80471372cf2972f1e697d512859afef..14211e382374609ac4166bb3900fde69bc3368cc 100644 (file)
@@ -46,33 +46,29 @@ void prom_putchar(char c)
        uart->iu_thr = c;
 }
 
-char __init prom_getchar(void)
+static void ioc3_console_write(struct console *con, const char *s, unsigned n)
 {
-       return 0;
+       while (n-- && *s) {
+               if (*s == '\n')
+                       prom_putchar('\r');
+               prom_putchar(*s);
+               s++;
+       }
 }
 
-static void inline ioc3_console_probe(void)
-{
-       struct uart_port up;
-
-       /*
-        * Register to interrupt zero because we share the interrupt with
-        * the serial driver which we don't properly support yet.
-        */
-       memset(&up, 0, sizeof(up));
-       up.membase      = (unsigned char *) console_uart();
-       up.irq          = 0;
-       up.uartclk      = IOC3_CLK;
-       up.regshift     = 0;
-       up.iotype       = UPIO_MEM;
-       up.flags        = IOC3_FLAGS;
-       up.line         = 0;
+static struct console ioc3_console = {
+       .name   = "ioc3",
+       .write  = ioc3_console_write,
+       .flags  = CON_PRINTBUFFER | CON_BOOT,
+       .index  = -1
+};
 
-       if (early_serial_setup(&up))
-               printk(KERN_ERR "Early serial init of port 0 failed\n");
+__init void ip27_setup_console(void)
+{
+       register_console(&ioc3_console);
 }
 
-__init void ip27_setup_console(void)
+void __init disable_early_printk(void)
 {
-       ioc3_console_probe();
+       unregister_console(&ioc3_console);
 }
index 0b61a39ce2bb1f116f991b94d481aa6cd2825096..869566c360ae9b5fe5a4e7b2d848498d39dda975 100644 (file)
@@ -386,7 +386,7 @@ void __devinit register_bridge_irq(unsigned int irq)
        irq_desc[irq].status    = IRQ_DISABLED;
        irq_desc[irq].action    = 0;
        irq_desc[irq].depth     = 1;
-       irq_desc[irq].handler   = &bridge_irq_type;
+       irq_desc[irq].chip      = &bridge_irq_type;
 }
 
 int __devinit request_bridge_irq(struct bridge_controller *bc)
index 8ba08047d164222b31bf6315b66fb51603d3a93a..00b94aaf6371834134736b909979397c9c7c52f9 100644 (file)
@@ -591,7 +591,7 @@ void __init arch_init_irq(void)
                irq_desc[irq].status = IRQ_DISABLED;
                irq_desc[irq].action = 0;
                irq_desc[irq].depth = 0;
-               irq_desc[irq].handler = controller;
+               irq_desc[irq].chip = controller;
        }
        setup_irq(CRIME_MEMERR_IRQ, &memerr_irq);
        setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq);
index 816aee7fcd25306009c409eec4d6a284c9b1676b..ec7a2cffacf01430485da171a33142ee9de5f1f6 100644 (file)
@@ -3,6 +3,7 @@ config SIBYTE_SB1250
        select HW_HAS_PCI
        select SIBYTE_HAS_LDT
        select SIBYTE_SB1xxx_SOC
+       select SYS_SUPPORTS_SMP
 
 config SIBYTE_BCM1120
        bool
@@ -30,11 +31,13 @@ config SIBYTE_BCM1x80
        bool
        select HW_HAS_PCI
        select SIBYTE_SB1xxx_SOC
+       select SYS_SUPPORTS_SMP
 
 config SIBYTE_BCM1x55
        bool
        select HW_HAS_PCI
        select SIBYTE_SB1xxx_SOC
+       select SYS_SUPPORTS_SMP
 
 config SIBYTE_SB1xxx_SOC
        bool
index e61760b14d99ec208d741e85f121f99cfb189838..610df40cb82088241ed6fdcb52e98ed30cef455d 100644 (file)
@@ -276,10 +276,10 @@ void __init init_bcm1480_irqs(void)
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
                if (i < BCM1480_NR_IRQS) {
-                       irq_desc[i].handler = &bcm1480_irq_type;
+                       irq_desc[i].chip = &bcm1480_irq_type;
                        bcm1480_irq_owner[i] = 0;
                } else {
-                       irq_desc[i].handler = &no_irq_type;
+                       irq_desc[i].chip = &no_irq_type;
                }
        }
 }
index f853c32f60a0f7e1b847f289a469b8e2b0932ada..fcc61940f1ff6444e8e03fed4cdf105a9cac555e 100644 (file)
@@ -246,10 +246,10 @@ void __init init_sb1250_irqs(void)
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
                if (i < SB1250_NR_IRQS) {
-                       irq_desc[i].handler = &sb1250_irq_type;
+                       irq_desc[i].chip = &sb1250_irq_type;
                        sb1250_irq_owner[i] = 0;
                } else {
-                       irq_desc[i].handler = &no_irq_type;
+                       irq_desc[i].chip = &no_irq_type;
                }
        }
 }
index 7365b4853ddb212a0d6073d49d60460838819f1f..c19e158ec402ad22dc2b6f60a7677f7102e7b72f 100644 (file)
@@ -203,7 +203,7 @@ void __init arch_init_irq(void)
                irq_desc[i].status     = IRQ_DISABLED;
                irq_desc[i].action     = 0;
                irq_desc[i].depth      = 1;
-               irq_desc[i].handler    = &pciasic_irq_type;
+               irq_desc[i].chip    = &pciasic_irq_type;
        }
 
        change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4);
index 8ca68015cf40ffd9456a17febfa107187eb8b18d..a42be00483e6d57f07bcdbe10b1267570939a974 100644 (file)
@@ -227,7 +227,7 @@ static void __init tx4927_irq_cp0_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &tx4927_irq_cp0_type;
+               irq_desc[i].chip = &tx4927_irq_cp0_type;
        }
 
        return;
@@ -435,7 +435,7 @@ static void __init tx4927_irq_pic_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 2;
-               irq_desc[i].handler = &tx4927_irq_pic_type;
+               irq_desc[i].chip = &tx4927_irq_pic_type;
        }
 
        setup_irq(TX4927_IRQ_NEST_PIC_ON_CP0, &tx4927_irq_pic_action);
index aee07ff2212a37bb1348a6a48d783dea94a8146e..c67978b6dae494b5ec08f6b175f759be3c941faf 100644 (file)
@@ -368,7 +368,7 @@ static void __init toshiba_rbtx4927_irq_ioc_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 3;
-               irq_desc[i].handler = &toshiba_rbtx4927_irq_ioc_type;
+               irq_desc[i].chip = &toshiba_rbtx4927_irq_ioc_type;
        }
 
        setup_irq(TOSHIBA_RBTX4927_IRQ_NEST_IOC_ON_PIC,
@@ -526,7 +526,7 @@ static void __init toshiba_rbtx4927_irq_isa_init(void)
                irq_desc[i].action = 0;
                irq_desc[i].depth =
                    ((i < TOSHIBA_RBTX4927_IRQ_ISA_MID) ? (4) : (5));
-               irq_desc[i].handler = &toshiba_rbtx4927_irq_isa_type;
+               irq_desc[i].chip = &toshiba_rbtx4927_irq_isa_type;
        }
 
        setup_irq(TOSHIBA_RBTX4927_IRQ_NEST_ISA_ON_IOC,
@@ -692,13 +692,13 @@ void toshiba_rbtx4927_irq_dump(char *key)
        {
                u32 i, j = 0;
                for (i = 0; i < NR_IRQS; i++) {
-                       if (strcmp(irq_desc[i].handler->typename, "none")
+                       if (strcmp(irq_desc[i].chip->typename, "none")
                            == 0)
                                continue;
 
                        if ((i >= 1)
-                           && (irq_desc[i - 1].handler->typename ==
-                               irq_desc[i].handler->typename)) {
+                           && (irq_desc[i - 1].chip->typename ==
+                               irq_desc[i].chip->typename)) {
                                j++;
                        } else {
                                j = 0;
@@ -707,12 +707,12 @@ void toshiba_rbtx4927_irq_dump(char *key)
                            (TOSHIBA_RBTX4927_IRQ_INFO,
                             "%s irq=0x%02x/%3d s=0x%08x h=0x%08x a=0x%08x ah=0x%08x d=%1d n=%s/%02d\n",
                             key, i, i, irq_desc[i].status,
-                            (u32) irq_desc[i].handler,
+                            (u32) irq_desc[i].chip,
                             (u32) irq_desc[i].action,
                             (u32) (irq_desc[i].action ? irq_desc[i].
                                    action->handler : 0),
                             irq_desc[i].depth,
-                            irq_desc[i].handler->typename, j);
+                            irq_desc[i].chip->typename, j);
                }
        }
 #endif
index 873805178d8e993b09402aad77ce8a9524f9bf83..0b2f8c8492181e4724b5675fdffed196ba207877 100644 (file)
@@ -102,7 +102,7 @@ tx4938_irq_cp0_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &tx4938_irq_cp0_type;
+               irq_desc[i].chip = &tx4938_irq_cp0_type;
        }
 
        return;
@@ -306,7 +306,7 @@ tx4938_irq_pic_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 2;
-               irq_desc[i].handler = &tx4938_irq_pic_type;
+               irq_desc[i].chip = &tx4938_irq_pic_type;
        }
 
        setup_irq(TX4938_IRQ_NEST_PIC_ON_CP0, &tx4938_irq_pic_action);
index 9cd9c0fe22658c9bcbcd6fbdb6e62a73f3ca609b..3b8245dc5bd38e9b074a4e12902bae0efb1082a9 100644 (file)
@@ -146,7 +146,7 @@ toshiba_rbtx4938_irq_ioc_init(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
                irq_desc[i].depth = 3;
-               irq_desc[i].handler = &toshiba_rbtx4938_irq_ioc_type;
+               irq_desc[i].chip = &toshiba_rbtx4938_irq_ioc_type;
        }
 
        setup_irq(RBTX4938_IRQ_IOCINT,
index 07ae19cf0c296d93422abe4db50f5d5c30c4f683..b9323302cc4e6fbf4b6312dab00b0617656ba4e3 100644 (file)
@@ -722,10 +722,10 @@ static int __init vr41xx_icu_init(void)
        icu2_write(MGIUINTHREG, 0xffff);
 
        for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++)
-               irq_desc[i].handler = &sysint1_irq_type;
+               irq_desc[i].chip = &sysint1_irq_type;
 
        for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++)
-               irq_desc[i].handler = &sysint2_irq_type;
+               irq_desc[i].chip = &sysint2_irq_type;
 
        cascade_irq(INT0_IRQ, icu_get_irq);
        cascade_irq(INT1_IRQ, icu_get_irq);
index 86796bb63c3c7e3d6b3aaa41626a52a43b8eca35..66aa50802deb6fcc06dd399a90b9c86a2a4a5d5a 100644 (file)
@@ -73,13 +73,13 @@ static void irq_dispatch(unsigned int irq, struct pt_regs *regs)
        if (cascade->get_irq != NULL) {
                unsigned int source_irq = irq;
                desc = irq_desc + source_irq;
-               desc->handler->ack(source_irq);
+               desc->chip->ack(source_irq);
                irq = cascade->get_irq(irq, regs);
                if (irq < 0)
                        atomic_inc(&irq_err_count);
                else
                        irq_dispatch(irq, regs);
-               desc->handler->end(source_irq);
+               desc->chip->end(source_irq);
        } else
                do_IRQ(irq, regs);
 }
index 3e31f8193d2115ef100674e6cddc015bd5acfa62..2d287b8893d90f4081c7742191e8ff2f24000af3 100644 (file)
@@ -483,7 +483,7 @@ static inline int vrc4173_icu_init(int cascade_irq)
        vr41xx_set_irq_level(GIU_IRQ_TO_PIN(cascade_irq), LEVEL_LOW);
 
        for (i = VRC4173_IRQ_BASE; i <= VRC4173_IRQ_LAST; i++)
-                irq_desc[i].handler = &vrc4173_irq_type;
+                irq_desc[i].chip = &vrc4173_irq_type;
 
        return 0;
 }
index 31db6b61a39e9627ad7c5da13e2e4de555880325..7b2511ca0a616a0c4729ba244d392fcbea0361ff 100644 (file)
@@ -104,7 +104,7 @@ void __init rockhopper_init_irq(void)
        }
 
        for (i = I8259_IRQ_BASE; i <= I8259_IRQ_LAST; i++)
-               irq_desc[i].handler = &i8259_irq_type;
+               irq_desc[i].chip = &i8259_irq_type;
 
        setup_irq(I8259_SLAVE_IRQ, &i8259_slave_cascade);
 
index 910fb3afc0b5c91e40c24a030a7b1b8241af5d60..6dd0ea8f88e0a49c273e3f04734efc3e42abb0d5 100644 (file)
@@ -51,6 +51,10 @@ config GENERIC_HARDIRQS
 config GENERIC_IRQ_PROBE
        def_bool y
 
+config IRQ_PER_CPU
+       bool
+       default y
+
 # unless you want to implement ACPI on PA-RISC ... ;-)
 config PM
        bool
index c057ad7605bab4e8e3d4d1ac1e987bced680f780..bc7c4a4e26a1e24f53b62b735bf820baac104635 100644 (file)
@@ -97,15 +97,17 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 void
 show_cache_info(struct seq_file *m)
 {
+       char buf[32];
+
        seq_printf(m, "I-cache\t\t: %ld KB\n", 
                cache_info.ic_size/1024 );
-       seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %d-way associative)\n", 
+       if (cache_info.dc_loop == 1)
+               snprintf(buf, 32, "%lu-way associative", cache_info.dc_loop);
+       seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %s)\n",
                cache_info.dc_size/1024,
                (cache_info.dc_conf.cc_wt ? "WT":"WB"),
                (cache_info.dc_conf.cc_sh ? ", shared I/D":""),
-               (cache_info.dc_conf.cc_assoc)
-       );
-
+               ((cache_info.dc_loop == 1) ? "direct mapped" : buf));
        seq_printf(m, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
                cache_info.it_size,
                cache_info.dt_size,
@@ -158,11 +160,11 @@ parisc_cache_init(void)
                cache_info.dc_conf.cc_block,
                cache_info.dc_conf.cc_line,
                cache_info.dc_conf.cc_shift);
-       printk("        wt %d sh %d cst %d assoc %d\n",
+       printk("        wt %d sh %d cst %d hv %d\n",
                cache_info.dc_conf.cc_wt,
                cache_info.dc_conf.cc_sh,
                cache_info.dc_conf.cc_cst,
-               cache_info.dc_conf.cc_assoc);
+               cache_info.dc_conf.cc_hv);
 
        printk("IC  base 0x%lx stride 0x%lx count 0x%lx loop 0x%lx\n",
                cache_info.ic_base,
@@ -176,11 +178,11 @@ parisc_cache_init(void)
                cache_info.ic_conf.cc_block,
                cache_info.ic_conf.cc_line,
                cache_info.ic_conf.cc_shift);
-       printk("        wt %d sh %d cst %d assoc %d\n",
+       printk("        wt %d sh %d cst %d hv %d\n",
                cache_info.ic_conf.cc_wt,
                cache_info.ic_conf.cc_sh,
                cache_info.ic_conf.cc_cst,
-               cache_info.ic_conf.cc_assoc);
+               cache_info.ic_conf.cc_hv);
 
        printk("D-TLB conf: sh %d page %d cst %d aid %d pad1 %d \n",
                cache_info.dt_conf.tc_sh,
@@ -234,7 +236,8 @@ parisc_cache_init(void)
 
 void disable_sr_hashing(void)
 {
-       int srhash_type;
+       int srhash_type, retval;
+       unsigned long space_bits;
 
        switch (boot_cpu_data.cpu_type) {
        case pcx: /* We shouldn't get this far.  setup.c should prevent it. */
@@ -260,6 +263,13 @@ void disable_sr_hashing(void)
        }
 
        disable_sr_hashing_asm(srhash_type);
+
+       retval = pdc_spaceid_bits(&space_bits);
+       /* If this procedure isn't implemented, don't panic. */
+       if (retval < 0 && retval != PDC_BAD_OPTION)
+               panic("pdc_spaceid_bits call failed.\n");
+       if (space_bits != 0)
+               panic("SpaceID hashing is still on!\n");
 }
 
 void flush_dcache_page(struct page *page)
index d9e53cf0372b313a368b886cc062fc33b419e5ab..630730c32a5a1e9d794f82ac5c9c7c15c3ab4831 100644 (file)
@@ -1638,7 +1638,7 @@ dbit_trap_20w:
        load32          PA(pa_dbit_lock),t0
 
 dbit_spin_20w:
-       ldcw            0(t0),t1
+       LDCW            0(t0),t1
        cmpib,=         0,t1,dbit_spin_20w
        nop
 
@@ -1674,7 +1674,7 @@ dbit_trap_11:
        load32          PA(pa_dbit_lock),t0
 
 dbit_spin_11:
-       ldcw            0(t0),t1
+       LDCW            0(t0),t1
        cmpib,=         0,t1,dbit_spin_11
        nop
 
@@ -1714,7 +1714,7 @@ dbit_trap_20:
        load32          PA(pa_dbit_lock),t0
 
 dbit_spin_20:
-       ldcw            0(t0),t1
+       LDCW            0(t0),t1
        cmpib,=         0,t1,dbit_spin_20
        nop
 
index 2dc06b8e18171f0e485d750d85f56be4ac197802..4398d2a95789b247c2676ae4f798631e45f77af0 100644 (file)
@@ -11,7 +11,7 @@
  * Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
  * Copyright 2003 Grant Grundler <grundler parisc-linux org>
  * Copyright 2003,2004 Ryan Bradetich <rbrad@parisc-linux.org>
- * Copyright 2004 Thibaut VARENE <varenet@parisc-linux.org>
+ * Copyright 2004,2006 Thibaut VARENE <varenet@parisc-linux.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
@@ -252,10 +252,8 @@ int pdc_pat_chassis_send_log(unsigned long state, unsigned long data)
 #endif
 
 /**
- * pdc_chassis_disp - Updates display
+ * pdc_chassis_disp - Updates chassis code
  * @retval: -1 on error, 0 on success
- *
- * Works on old PDC only (E class, others?)
  */
 int pdc_chassis_disp(unsigned long disp)
 {
@@ -268,6 +266,22 @@ int pdc_chassis_disp(unsigned long disp)
        return retval;
 }
 
+/**
+ * pdc_chassis_warn - Fetches chassis warnings
+ * @retval: -1 on error, 0 on success
+ */
+int pdc_chassis_warn(unsigned long *warn)
+{
+       int retval = 0;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(pdc_result));
+       *warn = pdc_result[0];
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
 /**
  * pdc_coproc_cfg - To identify coprocessors attached to the processor.
  * @pdc_coproc_info: Return buffer address.
@@ -393,7 +407,9 @@ int pdc_model_info(struct pdc_model *model)
  * pdc_model_sysmodel - Get the system model name.
  * @name: A char array of at least 81 characters.
  *
- * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L)
+ * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L).
+ * Using OS_ID_HPUX will return the equivalent of the 'modelname' command
+ * on HP/UX.
  */
 int pdc_model_sysmodel(char *name)
 {
@@ -498,6 +514,26 @@ int pdc_cache_info(struct pdc_cache_info *cache_info)
         return retval;
 }
 
+/**
+ * pdc_spaceid_bits - Return whether Space ID hashing is turned on.
+ * @space_bits: Should be 0, if not, bad mojo!
+ *
+ * Returns information about Space ID hashing.
+ */
+int pdc_spaceid_bits(unsigned long *space_bits)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       pdc_result[0] = 0;
+       retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_RET_SPID, __pa(pdc_result), 0);
+       convert_to_wide(pdc_result);
+       *space_bits = pdc_result[0];
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
 #ifndef CONFIG_PA20
 /**
  * pdc_btlb_info - Return block TLB information.
index 197936d9359a4065332a2c9a67ad8bd69ad04f33..82fe6ba29727a6824bd4a83e5fef44322239f08f 100644 (file)
@@ -94,7 +94,7 @@ int cpu_check_affinity(unsigned int irq, cpumask_t *dest)
        if (irq == TIMER_IRQ || irq == IPI_IRQ) {
                /* Bad linux design decision.  The mask has already
                 * been set; we must reset it */
-               irq_affinity[irq] = CPU_MASK_ALL;
+               irq_desc[irq].affinity = CPU_MASK_ALL;
                return -EINVAL;
        }
 
@@ -110,7 +110,7 @@ static void cpu_set_affinity_irq(unsigned int irq, cpumask_t dest)
        if (cpu_check_affinity(irq, &dest))
                return;
 
-       irq_affinity[irq] = dest;
+       irq_desc[irq].affinity = dest;
 }
 #endif
 
@@ -125,6 +125,10 @@ static struct hw_interrupt_type cpu_interrupt_type = {
 #ifdef CONFIG_SMP
        .set_affinity   = cpu_set_affinity_irq,
 #endif
+       /* XXX: Needs to be written.  We managed without it so far, but
+        * we really ought to write it.
+        */
+       .retrigger      = NULL,
 };
 
 int show_interrupts(struct seq_file *p, void *v)
@@ -158,7 +162,7 @@ int show_interrupts(struct seq_file *p, void *v)
                seq_printf(p, "%10u ", kstat_irqs(i));
 #endif
 
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
 #ifndef PARISC_IRQ_CR16_COUNTS
                seq_printf(p, "  %s", action->name);
 
@@ -210,12 +214,12 @@ int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data)
 {
        if (irq_desc[irq].action)
                return -EBUSY;
-       if (irq_desc[irq].handler != &cpu_interrupt_type)
+       if (irq_desc[irq].chip != &cpu_interrupt_type)
                return -EBUSY;
 
        if (type) {
-               irq_desc[irq].handler = type;
-               irq_desc[irq].handler_data = data;
+               irq_desc[irq].chip = type;
+               irq_desc[irq].chip_data = data;
                cpu_interrupt_type.enable(irq);
        }
        return 0;
@@ -265,7 +269,7 @@ int txn_alloc_irq(unsigned int bits_wide)
 unsigned long txn_affinity_addr(unsigned int irq, int cpu)
 {
 #ifdef CONFIG_SMP
-       irq_affinity[irq] = cpumask_of_cpu(cpu);
+       irq_desc[irq].affinity = cpumask_of_cpu(cpu);
 #endif
 
        return cpu_data[cpu].txn_addr;
@@ -326,7 +330,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
                /* Work our way from MSb to LSb...same order we alloc EIRs */
                for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
 #ifdef CONFIG_SMP
-                       cpumask_t dest = irq_affinity[irq];
+                       cpumask_t dest = irq_desc[irq].affinity;
 #endif
                        if (!(bit & eirr_val))
                                continue;
@@ -378,7 +382,7 @@ static void claim_cpu_irqs(void)
 {
        int i;
        for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
-               irq_desc[i].handler = &cpu_interrupt_type;
+               irq_desc[i].chip = &cpu_interrupt_type;
        }
 
        irq_desc[TIMER_IRQ].action = &timer_action;
@@ -404,13 +408,6 @@ void __init init_IRQ(void)
 
 }
 
-void hw_resend_irq(struct hw_interrupt_type *type, unsigned int irq)
-{
-       /* XXX: Needs to be written.  We managed without it so far, but
-        * we really ought to write it.
-        */
-}
-
 void ack_bad_irq(unsigned int irq)
 {
        printk("unexpected IRQ %d\n", irq);
index f27cfe4771b88c1099995e5964cb2541440da180..aee311884f3fa114c2a4fa5f5f4b0dc4fbe2d5f3 100644 (file)
@@ -89,6 +89,12 @@ static inline int is_local(struct module *me, void *loc)
        return is_init(me, loc) || is_core(me, loc);
 }
 
+static inline int is_local_section(struct module *me, void *loc, void *dot)
+{
+       return (is_init(me, loc) && is_init(me, dot)) ||
+               (is_core(me, loc) && is_core(me, dot));
+}
+
 
 #ifndef __LP64__
 struct got_entry {
@@ -364,8 +370,14 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value)
 }
 #endif /* __LP64__ */
 
+enum elf_stub_type {
+       ELF_STUB_GOT,
+       ELF_STUB_MILLI,
+       ELF_STUB_DIRECT,
+};
+
 static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
-       int millicode, int init_section)
+       enum elf_stub_type stub_type, int init_section)
 {
        unsigned long i;
        struct stub_entry *stub;
@@ -396,7 +408,7 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
        stub->insns[1] |= reassemble_17(rrsel(value, addend) / 4);
 
 #else
-/* for 64-bit we have two kinds of stubs:
+/* for 64-bit we have three kinds of stubs:
  * for normal function calls:
  *     ldd 0(%dp),%dp
  *     ldd 10(%dp), %r1
@@ -408,18 +420,23 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
  *     ldo 0(%r1), %r1
  *     ldd 10(%r1), %r1
  *     bve,n (%r1)
+ *
+ * for direct branches (jumps between different section of the
+ * same module):
+ *     ldil 0, %r1
+ *     ldo 0(%r1), %r1
+ *     bve,n (%r1)
  */
-       if (!millicode)
-       {
+       switch (stub_type) {
+       case ELF_STUB_GOT:
                stub->insns[0] = 0x537b0000;    /* ldd 0(%dp),%dp       */
                stub->insns[1] = 0x53610020;    /* ldd 10(%dp),%r1      */
                stub->insns[2] = 0xe820d000;    /* bve (%r1)            */
                stub->insns[3] = 0x537b0030;    /* ldd 18(%dp),%dp      */
 
                stub->insns[0] |= reassemble_14(get_got(me, value, addend) & 0x3fff);
-       }
-       else
-       {
+               break;
+       case ELF_STUB_MILLI:
                stub->insns[0] = 0x20200000;    /* ldil 0,%r1           */
                stub->insns[1] = 0x34210000;    /* ldo 0(%r1), %r1      */
                stub->insns[2] = 0x50210020;    /* ldd 10(%r1),%r1      */
@@ -427,7 +444,17 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
 
                stub->insns[0] |= reassemble_21(lrsel(value, addend));
                stub->insns[1] |= reassemble_14(rrsel(value, addend));
+               break;
+       case ELF_STUB_DIRECT:
+               stub->insns[0] = 0x20200000;    /* ldil 0,%r1           */
+               stub->insns[1] = 0x34210000;    /* ldo 0(%r1), %r1      */
+               stub->insns[2] = 0xe820d002;    /* bve,n (%r1)          */
+
+               stub->insns[0] |= reassemble_21(lrsel(value, addend));
+               stub->insns[1] |= reassemble_14(rrsel(value, addend));
+               break;
        }
+
 #endif
 
        return (Elf_Addr)stub;
@@ -539,14 +566,14 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
                        break;
                case R_PARISC_PCREL17F:
                        /* 17-bit PC relative address */
-                       val = get_stub(me, val, addend, 0, is_init(me, loc));
+                       val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc));
                        val = (val - dot - 8)/4;
                        CHECK_RELOC(val, 17)
                        *loc = (*loc & ~0x1f1ffd) | reassemble_17(val);
                        break;
                case R_PARISC_PCREL22F:
                        /* 22-bit PC relative address; only defined for pa20 */
-                       val = get_stub(me, val, addend, 0, is_init(me, loc));
+                       val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc));
                        DEBUGP("STUB FOR %s loc %lx+%lx at %lx\n", 
                               strtab + sym->st_name, (unsigned long)loc, addend, 
                               val)
@@ -643,13 +670,23 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
                               strtab + sym->st_name,
                               loc, val);
                        /* can we reach it locally? */
-                       if(!is_local(me, (void *)val)) {
-                               if (strncmp(strtab + sym->st_name, "$$", 2)
+                       if(!is_local_section(me, (void *)val, (void *)dot)) {
+
+                               if (is_local(me, (void *)val))
+                                       /* this is the case where the
+                                        * symbol is local to the
+                                        * module, but in a different
+                                        * section, so stub the jump
+                                        * in case it's more than 22
+                                        * bits away */
+                                       val = get_stub(me, val, addend, ELF_STUB_DIRECT,
+                                                      is_init(me, loc));
+                               else if (strncmp(strtab + sym->st_name, "$$", 2)
                                    == 0)
-                                       val = get_stub(me, val, addend, 1,
+                                       val = get_stub(me, val, addend, ELF_STUB_MILLI,
                                                       is_init(me, loc));
                                else
-                                       val = get_stub(me, val, addend, 0,
+                                       val = get_stub(me, val, addend, ELF_STUB_GOT,
                                                       is_init(me, loc));
                        }
                        DEBUGP("STUB FOR %s loc %lx, val %lx+%lx at %lx\n", 
index 79c7db2705fd4b7b475a87af50e09cf57cc62a4a..7d6967ee367c7f8ef5784281d0eb082af7a9a9b2 100644 (file)
@@ -289,7 +289,7 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
  * than res->start.
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                               unsigned long size, unsigned long alignment)
+                               resource_size_t size, resource_size_t alignment)
 {
        unsigned long mask, align;
 
index a45e2e2ffd9f7ff21c2caf748b9e8ce01aa210ce..d47ba1aa825376fdce235befca626b6cb95762d8 100644 (file)
@@ -1,8 +1,8 @@
 /* 
- *    interfaces to log Chassis Codes via PDC (firmware)
+ *    interfaces to Chassis Codes via PDC (firmware)
  *
  *    Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
- *    Copyright (C) 2002-2004 Thibaut VARENE <varenet@parisc-linux.org>
+ *    Copyright (C) 2002-2006 Thibaut VARENE <varenet@parisc-linux.org>
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License, version 2, as
  *    You 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
+ *
+ *    TODO: poll chassis warns, trigger (configurable) machine shutdown when
+ *             needed.
+ *         Find out how to get Chassis warnings out of PAT boxes?
  */
 
 #undef PDC_CHASSIS_DEBUG
 #include <linux/reboot.h>
 #include <linux/notifier.h>
 #include <linux/cache.h>
+#include <linux/proc_fs.h>
 
 #include <asm/pdc_chassis.h>
 #include <asm/processor.h>
 #include <asm/pdc.h>
 #include <asm/pdcpat.h>
 
+#define PDC_CHASSIS_VER        "0.05"
 
 #ifdef CONFIG_PDC_CHASSIS
-static int pdc_chassis_old __read_mostly = 0;  
 static unsigned int pdc_chassis_enabled __read_mostly = 1;
 
 
@@ -64,7 +69,7 @@ __setup("pdcchassis=", pdc_chassis_setup);
  * Currently, only E class and A180 are known to work with this.
  * Inspired by Christoph Plattner
  */
-
+#if 0
 static void __init pdc_chassis_checkold(void)
 {
        switch(CPU_HVERSION) {
@@ -73,7 +78,6 @@ static void __init pdc_chassis_checkold(void)
                case 0x482:             /* E45 */
                case 0x483:             /* E55 */
                case 0x516:             /* A180 */
-                       pdc_chassis_old = 1;
                        break;
 
                default:
@@ -81,7 +85,7 @@ static void __init pdc_chassis_checkold(void)
        }
        DPRINTK(KERN_DEBUG "%s: pdc_chassis_checkold(); pdc_chassis_old = %d\n", __FILE__, pdc_chassis_old);
 }
-
+#endif
 
 /**
  * pdc_chassis_panic_event() - Called by the panic handler.
@@ -131,30 +135,20 @@ static struct notifier_block pdc_chassis_reboot_block = {
 void __init parisc_pdc_chassis_init(void)
 {
 #ifdef CONFIG_PDC_CHASSIS
-       int handle = 0;
        if (likely(pdc_chassis_enabled)) {
                DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__);
 
                /* Let see if we have something to handle... */
-               /* Check for PDC_PAT or old LED Panel */
-               pdc_chassis_checkold();
-               if (is_pdc_pat()) {
-                       printk(KERN_INFO "Enabling PDC_PAT chassis codes support.\n");
-                       handle = 1;
-               }
-               else if (unlikely(pdc_chassis_old)) {
-                       printk(KERN_INFO "Enabling old style chassis LED panel support.\n");
-                       handle = 1;
-               }
-
-               if (handle) {
-                       /* initialize panic notifier chain */
-                       atomic_notifier_chain_register(&panic_notifier_list,
-                                       &pdc_chassis_panic_block);
-
-                       /* initialize reboot notifier chain */
-                       register_reboot_notifier(&pdc_chassis_reboot_block);
-               }
+               printk(KERN_INFO "Enabling %s chassis codes support v%s\n",
+                               is_pdc_pat() ? "PDC_PAT" : "regular",
+                               PDC_CHASSIS_VER);
+
+               /* initialize panic notifier chain */
+               atomic_notifier_chain_register(&panic_notifier_list,
+                               &pdc_chassis_panic_block);
+
+               /* initialize reboot notifier chain */
+               register_reboot_notifier(&pdc_chassis_reboot_block);
        }
 #endif /* CONFIG_PDC_CHASSIS */
 }
@@ -215,9 +209,12 @@ int pdc_chassis_send_status(int message)
                        }
                } else retval = -1;
 #else
-               if (unlikely(pdc_chassis_old)) {
+               if (1) {
                        switch (message) {
                                case PDC_CHASSIS_DIRECT_BSTART:
+                                       retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_INIT));
+                                       break;
+
                                case PDC_CHASSIS_DIRECT_BCOMPLETE:
                                        retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN));
                                        break;
@@ -244,3 +241,61 @@ int pdc_chassis_send_status(int message)
 #endif /* CONFIG_PDC_CHASSIS */
        return retval;
 }
+
+#ifdef CONFIG_PDC_CHASSIS_WARN
+#ifdef CONFIG_PROC_FS
+static int pdc_chassis_warn_pread(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       char *out = page;
+       int len, ret;
+       unsigned long warn;
+       u32 warnreg;
+
+       ret = pdc_chassis_warn(&warn);
+       if (ret != PDC_OK)
+               return -EIO;
+
+       warnreg = (warn & 0xFFFFFFFF);
+
+       if ((warnreg >> 24) & 0xFF)
+               out += sprintf(out, "Chassis component failure! (eg fan or PSU): 0x%.2x\n", ((warnreg >> 24) & 0xFF));
+
+       out += sprintf(out, "Battery: %s\n", (warnreg & 0x04) ? "Low!" : "OK");
+       out += sprintf(out, "Temp low: %s\n", (warnreg & 0x02) ? "Exceeded!" : "OK");
+       out += sprintf(out, "Temp mid: %s\n", (warnreg & 0x01) ? "Exceeded!" : "OK");
+
+       len = out - page - off;
+       if (len < count) {
+               *eof = 1;
+               if (len <= 0) return 0;
+       } else {
+               len = count;
+       }
+       *start = page + off;
+       return len;
+}
+
+static int __init pdc_chassis_create_procfs(void)
+{
+       unsigned long test;
+       int ret;
+
+       ret = pdc_chassis_warn(&test);
+       if ((ret == PDC_BAD_PROC) || (ret == PDC_BAD_OPTION)) {
+               /* seems that some boxes (eg L1000) do not implement this */
+               printk(KERN_INFO "Chassis warnings not supported.\n");
+               return 0;
+       }
+
+       printk(KERN_INFO "Enabling PDC chassis warnings support v%s\n",
+                       PDC_CHASSIS_VER);
+       create_proc_read_entry("chassis", 0400, NULL, pdc_chassis_warn_pread,
+                               NULL);
+       return 0;
+}
+
+__initcall(pdc_chassis_create_procfs);
+
+#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_PDC_CHASSIS_WARN */
index 413292f1a4a36401fda3cc03129574b68e648f09..3f28de974556c838894ab5d12f40227d2c39c23e 100644 (file)
@@ -91,7 +91,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                int copied;
 
 #ifdef __LP64__
-               if (personality(child->personality) == PER_LINUX32) {
+               if (__is_compat_task(child)) {
                        unsigned int tmp;
 
                        addr &= 0xffffffffL;
@@ -123,7 +123,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        case PTRACE_POKEDATA:
                ret = 0;
 #ifdef __LP64__
-               if (personality(child->personality) == PER_LINUX32) {
+               if (__is_compat_task(child)) {
                        unsigned int tmp = (unsigned int)data;
                        DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
                                request == PTRACE_POKETEXT ? "TEXT" : "DATA",
@@ -146,7 +146,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        case PTRACE_PEEKUSR: {
                ret = -EIO;
 #ifdef __LP64__
-               if (personality(child->personality) == PER_LINUX32) {
+               if (__is_compat_task(child)) {
                        unsigned int tmp;
 
                        if (addr & (sizeof(int)-1))
@@ -205,7 +205,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        goto out_tsk;
                }
 #ifdef __LP64__
-               if (personality(child->personality) == PER_LINUX32) {
+               if (__is_compat_task(child)) {
                        if (addr & (sizeof(int)-1))
                                goto out_tsk;
                        if ((addr = translate_usr_offset(addr)) < 0)
index 8c2859cca77ee69ab0dfbcbb2af84cf2e70c76b8..453d01a9f97149ce44ea848667c1b3661e072e6f 100644 (file)
@@ -276,15 +276,6 @@ r64_ret:
 
 #endif
 
-       .export pc_in_user_space
-       .text
-       /* Doesn't belong here but I couldn't find a nicer spot. */
-       /* Should never get called, only used by profile stuff in time.c */
-pc_in_user_space:
-       bv,n    0(%rp)
-       nop
-
-
        .export __canonicalize_funcptr_for_compare
        .text
        /* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html
index 4a36ec3f6ac15f9ae0466fcfc2992374a3962601..278f4b9f6a3878806c7199c8dedec4e48d41d8be 100644 (file)
@@ -303,6 +303,8 @@ extern void eisa_init(void);
 
 static int __init parisc_init(void)
 {
+       u32 osid = (OS_ID_LINUX << 16);
+
        parisc_proc_mkdir();
        parisc_init_resources();
        do_device_inventory();                  /* probe for hardware */
@@ -311,6 +313,9 @@ static int __init parisc_init(void)
        
        /* set up a new led state on systems shipped LED State panel */
        pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART);
+
+       /* tell PDC we're Linux. Nevermind failure. */
+       pdc_stable_write(0x40, &osid, sizeof(osid));
        
        processor_init();
        printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n",
index cc38edfd90c5bcac048647d5dacb298254314c8b..bb83880c5ee3458bd9940b96e527bf9146cb96e9 100644 (file)
@@ -76,7 +76,7 @@ sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *r
 #ifdef __LP64__
        compat_sigset_t newset32;
 
-       if(personality(current->personality) == PER_LINUX32){
+       if (is_compat_task()) {
                /* XXX: Don't preclude handling different sized sigset_t's.  */
                if (sigsetsize != sizeof(compat_sigset_t))
                        return -EINVAL;
@@ -153,7 +153,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
        compat_sigset_t compat_set;
        struct compat_rt_sigframe __user * compat_frame;
        
-       if(personality(current->personality) == PER_LINUX32)
+       if (is_compat_task())
                sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
 #endif
 
@@ -166,7 +166,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
 #ifdef __LP64__
        compat_frame = (struct compat_rt_sigframe __user *)frame;
        
-       if(personality(current->personality) == PER_LINUX32){
+       if (is_compat_task()) {
                DBG(2,"sys_rt_sigreturn: ELF32 process.\n");
                if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask, sizeof(compat_set)))
                        goto give_sigsegv;
@@ -186,7 +186,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
 
        /* Good thing we saved the old gr[30], eh? */
 #ifdef __LP64__
-       if(personality(current->personality) == PER_LINUX32){
+       if (is_compat_task()) {
                DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n",
                                &compat_frame->uc.uc_mcontext);
 // FIXME: Load upper half from register file
@@ -315,7 +315,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 
        compat_frame = (struct compat_rt_sigframe __user *)frame;
        
-       if(personality(current->personality) == PER_LINUX32) {
+       if (is_compat_task()) {
                DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
                err |= copy_siginfo_to_user32(&compat_frame->info, info);
                DBG(1,"SETUP_RT_FRAME: 1\n");
@@ -392,7 +392,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        haddr = A(ka->sa.sa_handler);
        /* The sa_handler may be a pointer to a function descriptor */
 #ifdef __LP64__
-       if(personality(current->personality) == PER_LINUX32) {
+       if (is_compat_task()) {
 #endif
                if (haddr & PA_PLABEL_FDESC) {
                        Elf32_Fdesc fdesc;
@@ -427,19 +427,19 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
         */
        sigframe_size = PARISC_RT_SIGFRAME_SIZE;
 #ifdef __LP64__
-       if(personality(current->personality) == PER_LINUX32)
+       if (is_compat_task())
                sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
 #endif
        if (in_syscall) {
                regs->gr[31] = haddr;
 #ifdef __LP64__
-               if(personality(current->personality) == PER_LINUX)
+               if (personality(current->personality) == PER_LINUX)
                        sigframe_size |= 1;
 #endif
        } else {
                unsigned long psw = USER_PSW;
 #ifdef __LP64__
-               if(personality(current->personality) == PER_LINUX)
+               if (personality(current->personality) == PER_LINUX)
                        psw |= PSW_W;
 #endif
 
@@ -464,7 +464,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->gr[26] = sig;               /* signal number */
        
 #ifdef __LP64__
-       if(personality(current->personality) == PER_LINUX32){
+       if (is_compat_task()) {
                regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */
                regs->gr[24] = A(&compat_frame->uc);   /* ucontext pointer */
        } else
index 479d9a017cd1ff3e19ea90c30f579a7b64f7acbb..9670a89c77fe480255ce79cf5a8705434e06d43e 100644 (file)
        .level          1.1
 #endif
 
-#ifndef CONFIG_64BIT
-       .macro fixup_branch,lbl
-       b           \lbl
-       .endm
-#else
-       .macro fixup_branch,lbl
-       ldil        L%\lbl, %r1
-       ldo         R%\lbl(%r1), %r1
-       bv,n        %r0(%r1)
-       .endm
-#endif
-
        .text
 
        .import syscall_exit,code
@@ -541,7 +529,7 @@ cas_nocontend:
 # endif
 /* ENABLE_LWS_DEBUG */
 
-       ldcw    0(%sr2,%r20), %r28                      /* Try to acquire the lock */
+       LDCW    0(%sr2,%r20), %r28                      /* Try to acquire the lock */
        cmpb,<>,n       %r0, %r28, cas_action           /* Did we get it? */
 cas_wouldblock:
        ldo     2(%r0), %r28                            /* 2nd case */
index 594930bc4bcf6d3df7231e0545bdbfbf5bb3842b..eb35e1c0bb532b679b660351fc5e28db1e6ee8b8 100644 (file)
@@ -157,8 +157,22 @@ do_gettimeofday (struct timeval *tv)
                usec += (xtime.tv_nsec / 1000);
        } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
 
-       while (usec >= 1000000) {
-               usec -= 1000000;
+       if (unlikely(usec > LONG_MAX)) {
+               /* This can happen if the gettimeoffset adjustment is
+                * negative and xtime.tv_nsec is smaller than the
+                * adjustment */
+               printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec);
+               usec += USEC_PER_SEC;
+               --sec;
+               /* This should never happen, it means the negative
+                * time adjustment was more than a second, so there's
+                * something seriously wrong */
+               BUG_ON(usec > LONG_MAX);
+       }
+
+
+       while (usec >= USEC_PER_SEC) {
+               usec -= USEC_PER_SEC;
                ++sec;
        }
 
index 3ba040050e4ca1d85a28448accea66e50a0ce0fb..068b20d822e7b9c672983135a0c038e11e491839 100644 (file)
@@ -26,11 +26,10 @@ static struct cpu cpu_devices[NR_CPUS] __read_mostly;
 
 static int __init topology_init(void)
 {
-       struct node *parent = NULL;
        int num;
 
        for_each_present_cpu(num) {
-               register_cpu(&cpu_devices[num], num, parent);
+               register_cpu(&cpu_devices[num], num);
        }
        return 0;
 }
index ff200608c851d5ef948908ff8b1b38f6fe2e56f2..348344a84bf7615fa4a31cbf2cb81cc3ca378ff9 100644 (file)
@@ -66,57 +66,42 @@ int printbinary(char *buf, unsigned long x, int nbits)
 #else
 #define RFMT "%08lx"
 #endif
+#define FFMT "%016llx" /* fpregs are 64-bit always */
 
-void show_regs(struct pt_regs *regs)
+#define PRINTREGS(lvl,r,f,fmt,x)       \
+       printk("%s%s%02d-%02d  " fmt " " fmt " " fmt " " fmt "\n",      \
+               lvl, f, (x), (x+3), (r)[(x)+0], (r)[(x)+1],             \
+               (r)[(x)+2], (r)[(x)+3])
+
+static void print_gr(char *level, struct pt_regs *regs)
 {
        int i;
-       char buf[128], *p;
-       char *level;
-       unsigned long cr30;
-       unsigned long cr31;
-       /* carlos says that gcc understands better memory in a struct,
-        * and it makes our life easier with fpregs -- T-Bone */
-       struct { u32 sw[2]; } s;
-       
-       level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
-
-       printk("%s\n", level); /* don't want to have that pretty register dump messed up */
+       char buf[64];
 
+       printk("%s\n", level);
        printk("%s     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level);
        printbinary(buf, regs->gr[0], 32);
        printk("%sPSW: %s %s\n", level, buf, print_tainted());
 
-       for (i = 0; i < 32; i += 4) {
-               int j;
-               p = buf;
-               p += sprintf(p, "%sr%02d-%02d ", level, i, i + 3);
-               for (j = 0; j < 4; j++) {
-                       p += sprintf(p, " " RFMT, (i+j) == 0 ? 0 : regs->gr[i + j]);
-               }
-               printk("%s\n", buf);
-       }
+       for (i = 0; i < 32; i += 4)
+               PRINTREGS(level, regs->gr, "r", RFMT, i);
+}
 
-       for (i = 0; i < 8; i += 4) {
-               int j;
-               p = buf;
-               p += sprintf(p, "%ssr%d-%d  ", level, i, i + 3);
-               for (j = 0; j < 4; j++) {
-                       p += sprintf(p, " " RFMT, regs->sr[i + j]);
-               }
-               printk("%s\n", buf);
-       }
+static void print_fr(char *level, struct pt_regs *regs)
+{
+       int i;
+       char buf[64];
+       struct { u32 sw[2]; } s;
 
        /* FR are 64bit everywhere. Need to use asm to get the content
         * of fpsr/fper1, and we assume that we won't have a FP Identify
         * in our way, otherwise we're screwed.
         * The fldd is used to restore the T-bit if there was one, as the
         * store clears it anyway.
-        * BTW, PA2.0 book says "thou shall not use fstw on FPSR/FPERs". */ 
-       __asm__ (
-               "fstd %%fr0,0(%1)       \n\t"
-               "fldd 0(%1),%%fr0       \n\t"
-               : "=m" (s) : "r" (&s) : "%r0"
-               );
+        * PA2.0 book says "thou shall not use fstw on FPSR/FPERs" - T-Bone */
+       asm volatile ("fstd %%fr0,0(%1) \n\t"
+                     "fldd 0(%1),%%fr0 \n\t"
+                     : "=m" (s) : "r" (&s) : "r0");
 
        printk("%s\n", level);
        printk("%s      VZOUICununcqcqcqcqcqcrmunTDVZOUI\n", level);
@@ -125,14 +110,25 @@ void show_regs(struct pt_regs *regs)
        printk("%sFPER1: %08x\n", level, s.sw[1]);
 
        /* here we'll print fr0 again, tho it'll be meaningless */
-       for (i = 0; i < 32; i += 4) {
-               int j;
-               p = buf;
-               p += sprintf(p, "%sfr%02d-%02d ", level, i, i + 3);
-               for (j = 0; j < 4; j++)
-                       p += sprintf(p, " %016llx", (i+j) == 0 ? 0 : regs->fr[i+j]);
-               printk("%s\n", buf);
-       }
+       for (i = 0; i < 32; i += 4)
+               PRINTREGS(level, regs->fr, "fr", FFMT, i);
+}
+
+void show_regs(struct pt_regs *regs)
+{
+       int i;
+       char *level;
+       unsigned long cr30, cr31;
+
+       level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
+
+       print_gr(level, regs);
+
+       for (i = 0; i < 8; i += 4)
+               PRINTREGS(level, regs->sr, "sr", RFMT, i);
+
+       if (user_mode(regs))
+               print_fr(level, regs);
 
        cr30 = mfctl(30);
        cr31 = mfctl(31);
index de0a1b21cb40cba92615f550a626a0612207d0cf..92328fbddb3e8becf3ffa346a02d7d9988624e38 100644 (file)
@@ -43,6 +43,8 @@
        "\tldil L%%" #lbl ", %%r1\n"                    \
        "\tldo R%%" #lbl "(%%r1), %%r1\n"               \
        "\tbv,n %%r0(%%r1)\n"
+/* If you use FIXUP_BRANCH, then you must list this clobber */
+#define FIXUP_BRANCH_CLOBBER "r1"
 
 /* 1111 1100 0000 0000 0001 0011 1100 0000 */
 #define OPCODE1(a,b,c) ((a)<<26|(b)<<12|(c)<<6) 
@@ -157,7 +159,7 @@ static int emulate_ldh(struct pt_regs *regs, int toreg)
 "      .previous\n"
        : "=r" (val), "=r" (ret)
        : "0" (val), "r" (saddr), "r" (regs->isr)
-       : "r20" );
+       : "r20", FIXUP_BRANCH_CLOBBER );
 
        DPRINTF("val = 0x" RFMT "\n", val);
 
@@ -202,7 +204,7 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
 "      .previous\n"
        : "=r" (val), "=r" (ret)
        : "0" (val), "r" (saddr), "r" (regs->isr)
-       : "r19", "r20" );
+       : "r19", "r20", FIXUP_BRANCH_CLOBBER );
 
        DPRINTF("val = 0x" RFMT "\n", val);
 
@@ -253,7 +255,7 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 "      .previous\n"
        : "=r" (val), "=r" (ret)
        : "0" (val), "r" (saddr), "r" (regs->isr)
-       : "r19", "r20" );
+       : "r19", "r20", FIXUP_BRANCH_CLOBBER );
 #else
     {
        unsigned long valh=0,vall=0;
@@ -287,7 +289,7 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 "      .previous\n"
        : "=r" (valh), "=r" (vall), "=r" (ret)
        : "0" (valh), "1" (vall), "r" (saddr), "r" (regs->isr)
-       : "r19", "r20" );
+       : "r19", "r20", FIXUP_BRANCH_CLOBBER );
        val=((__u64)valh<<32)|(__u64)vall;
     }
 #endif
@@ -335,7 +337,7 @@ static int emulate_sth(struct pt_regs *regs, int frreg)
 "      .previous\n"
        : "=r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
-       : "r19" );
+       : "r19", FIXUP_BRANCH_CLOBBER );
 
        return ret;
 }
@@ -389,7 +391,7 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop)
 "      .previous\n"
        : "=r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
-       : "r19", "r20", "r21", "r22", "r1" );
+       : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
 
        return 0;
 }
@@ -450,7 +452,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "      .previous\n"
        : "=r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
-       : "r19", "r20", "r21", "r22", "r1" );
+       : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
 #else
     {
        unsigned long valh=(val>>32),vall=(val&0xffffffffl);
@@ -495,7 +497,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "      .previous\n"
        : "=r" (ret)
        : "r" (valh), "r" (vall), "r" (regs->ior), "r" (regs->isr)
-       : "r19", "r20", "r21", "r1" );
+       : "r19", "r20", "r21", "r1", FIXUP_BRANCH_CLOBBER );
     }
 #endif
 
index e922a88b2bad33fc4b17855600a9826f19b4c42d..2643dbc3f289428ef46d836705e93e386904dafe 100644 (file)
@@ -30,6 +30,10 @@ config GENERIC_HARDIRQS
        bool
        default y
 
+config IRQ_PER_CPU
+       bool
+       default y
+
 config RWSEM_GENERIC_SPINLOCK
        bool
 
@@ -336,7 +340,7 @@ config PPC_ISERIES
 
 config EMBEDDED6xx
        bool "Embedded 6xx/7xx/7xxx-based board"
-       depends on PPC32 && BROKEN
+       depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
 
 config APUS
        bool "Amiga-APUS"
@@ -413,12 +417,17 @@ config PPC_CELL_NATIVE
        default n
 
 config PPC_IBM_CELL_BLADE
-       bool "  IBM Cell Blade"
+       bool "IBM Cell Blade"
        depends on PPC_MULTIPLATFORM && PPC64
        select PPC_CELL_NATIVE
        select PPC_RTAS
        select MMIO_NVRAM
        select PPC_UDBG_16550
+       select UDBG_RTAS_CONSOLE
+
+config UDBG_RTAS_CONSOLE
+       bool
+       default n
 
 config XICS
        depends on PPC_PSERIES
@@ -431,7 +440,8 @@ config U3_DART
        default n
 
 config MPIC
-       depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE || PPC_CHRP
+       depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE || PPC_CHRP \
+                              || MPC7448HPC2
        bool
        default y
 
@@ -557,6 +567,13 @@ config TAU_AVERAGE
          /proc/cpuinfo.
 
          If in doubt, say N here.
+
+config PPC_TODC
+       depends on EMBEDDED6xx
+       bool "Generic Time-of-day Clock (TODC) support"
+       ---help---
+         This adds support for many TODC/RTC chips.
+
 endmenu
 
 source arch/powerpc/platforms/embedded6xx/Kconfig
@@ -618,16 +635,19 @@ config HOTPLUG_CPU
 
          Say N if you are unsure.
 
+config ARCH_ENABLE_MEMORY_HOTPLUG
+       def_bool y
+
 config KEXEC
        bool "kexec system call (EXPERIMENTAL)"
        depends on PPC_MULTIPLATFORM && EXPERIMENTAL
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
-         but it is indepedent of the system firmware.   And like a reboot
+         but it is independent of the system firmware.   And like a reboot
          you can start any kernel with it, not just Linux.
 
-         The name comes from the similiarity to the exec system call.
+         The name comes from the similarity to the exec system call.
 
          It is an ongoing process to be certain the hardware in a machine
          is properly shutdown, so do not be surprised if this code does not
@@ -794,7 +814,6 @@ config GENERIC_ISA_DMA
 
 config PPC_I8259
        bool
-       default y if MPC8641_HPCN
        default n
 
 config PPC_INDIRECT_PCI
@@ -817,7 +836,8 @@ config MCA
        bool
 
 config PCI
-       bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES)
+       bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES) \
+                                 || MPC7448HPC2
        default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !PPC_85xx && !PPC_86xx
        default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
        default PCI_QSPAN if !4xx && !CPM2 && 8xx
index c69006ae8246abc6bbc756752779473bf5c4467c..e29ef77d3b0016ef7d164ce28b5176194e6efeb7 100644 (file)
@@ -134,12 +134,19 @@ config PPC_EARLY_DEBUG_G5
        help
          Select this to enable early debugging for Apple G5 machines.
 
-config PPC_EARLY_DEBUG_RTAS
+config PPC_EARLY_DEBUG_RTAS_PANEL
        bool "RTAS Panel"
        depends on PPC_RTAS
        help
          Select this to enable early debugging via the RTAS panel.
 
+config PPC_EARLY_DEBUG_RTAS_CONSOLE
+       bool "RTAS Console"
+       depends on PPC_RTAS
+       select UDBG_RTAS_CONSOLE
+       help
+         Select this to enable early debugging via the RTAS console.
+
 config PPC_EARLY_DEBUG_MAPLE
        bool "Maple real mode"
        depends on PPC_MAPLE
index b8b8d4675dc04f201a674c4a72f6e07607d8efee..e028a2ecb8a356694218bdfc97005277d1da2630 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.17
-# Mon Jun 19 17:23:03 2006
+# Linux kernel version: 2.6.17-rc6
+# Thu Jun 22 15:28:36 2006
 #
 CONFIG_PPC64=y
 CONFIG_64BIT=y
@@ -1063,7 +1063,8 @@ CONFIG_DEBUG_FS=y
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUGGER=y
-# CONFIG_XMON is not set
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
 CONFIG_IRQSTACKS=y
 # CONFIG_BOOTX_TEXT is not set
 # CONFIG_PPC_EARLY_DEBUG is not set
diff --git a/arch/powerpc/configs/mpc7448_hpc2_defconfig b/arch/powerpc/configs/mpc7448_hpc2_defconfig
new file mode 100644 (file)
index 0000000..15a50f4
--- /dev/null
@@ -0,0 +1,923 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17-rc4
+# Sat May 27 18:45:55 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_PPC_FPU=y
+# CONFIG_ALTIVEC is not set
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Platform support
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_PPC_ISERIES is not set
+CONFIG_EMBEDDED6xx=y
+# CONFIG_APUS is not set
+CONFIG_MPIC=y
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_TAU is not set
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_CHESTNUT is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_HDPU is not set
+# CONFIG_EV64260 is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+CONFIG_MPC7448HPC2=y
+# CONFIG_RADSTONE_PPC7D is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX8260 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
+# CONFIG_EV64360 is not set
+CONFIG_TSI108_BRIDGE=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_INDIRECT_PCI is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=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_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=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_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# 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_MEGARAID_SAS is not set
+CONFIG_SCSI_SATA=y
+# CONFIG_SCSI_SATA_AHCI is not set
+# CONFIG_SCSI_SATA_SVW is not set
+# CONFIG_SCSI_ATA_PIIX is not set
+CONFIG_SCSI_SATA_MV=y
+# CONFIG_SCSI_SATA_NV is not set
+# CONFIG_SCSI_PDC_ADMA is not set
+# CONFIG_SCSI_SATA_QSTOR is not set
+# CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_SATA_SX4 is not set
+# CONFIG_SCSI_SATA_SIL is not set
+# CONFIG_SCSI_SATA_SIL24 is not set
+# CONFIG_SCSI_SATA_SIS is not set
+# CONFIG_SCSI_SATA_ULI is not set
+# CONFIG_SCSI_SATA_VIA is not set
+# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA 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_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC 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
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+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
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY 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_CASSINI 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_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET 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
+
+#
+# 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_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_TSI108_ETH=y
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER 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 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
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_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_JSM 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_NVRAM is not set
+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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_HWMON_DEBUG_CHIP 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
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# 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 is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# 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 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_NFS_COMMON=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_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_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_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
+# CONFIG_PPC_EARLY_DEBUG_G5 is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS is not set
+# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
+# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
index 803858e8616031054c62fbb04021e0d6a3f13052..814f242aeb8cc06348603c2df8478b0dd0d4e274 100644 (file)
@@ -50,7 +50,8 @@ extra-$(CONFIG_FSL_BOOKE)     := head_fsl_booke.o
 extra-$(CONFIG_8xx)            := head_8xx.o
 extra-y                                += vmlinux.lds
 
-obj-y                          += time.o prom.o traps.o setup-common.o udbg.o
+obj-y                          += time.o prom.o traps.o setup-common.o \
+                                  udbg.o misc.o
 obj-$(CONFIG_PPC32)            += entry_32.o setup_32.o misc_32.o
 obj-$(CONFIG_PPC64)            += misc_64.o dma_64.o iommu.o
 obj-$(CONFIG_PPC_MULTIPLATFORM)        += prom_init.o
index 271418308d536de53601ae69a0c070ac24a11490..1fc8632610030c7da76bd33933ecfda1b5373c35 100644 (file)
@@ -125,7 +125,12 @@ _GLOBAL(__save_cpu_setup)
        cmpwi   r0,0x44
        bne     2f
 
-1:     /* Save HID0,1,4 and 5 */
+1:     /* skip if not running in HV mode */
+       mfmsr   r0
+       rldicl. r0,r0,4,63
+       beq     2f
+
+       /* Save HID0,1,4 and 5 */
        mfspr   r3,SPRN_HID0
        std     r3,CS_HID0(r5)
        mfspr   r3,SPRN_HID1
@@ -159,7 +164,12 @@ _GLOBAL(__restore_cpu_setup)
        cmpwi   r0,0x44
        bnelr
 
-1:     /* Before accessing memory, we make sure rm_ci is clear */
+1:     /* skip if not running in HV mode */
+       mfmsr   r0
+       rldicl. r0,r0,4,63
+       beqlr
+
+       /* Before accessing memory, we make sure rm_ci is clear */
        li      r0,0
        mfspr   r3,SPRN_HID4
        rldimi  r3,r0,40,23     /* clear bit 23 (rm_ci) */
index 1c114880dc0504fe7d8e5c64b851ad23fdc69cab..abf7d42a8b07f6bee788f8ced65656188ef59aae 100644 (file)
@@ -722,18 +722,6 @@ struct cpu_spec    cpu_specs[] = {
                .oprofile_type          = PPC_OPROFILE_G4,
                .platform               = "ppc7450",
        },
-        {       /* 8641 */
-               .pvr_mask               = 0xffffffff,
-               .pvr_value              = 0x80040010,
-               .cpu_name               = "8641",
-               .cpu_features           = CPU_FTRS_7447A,
-               .cpu_user_features      = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
-               .icache_bsize           = 32,
-               .dcache_bsize           = 32,
-               .num_pmcs               = 6,
-               .cpu_setup              = __setup_cpu_745x
-        },
-
        {       /* 82xx (8240, 8245, 8260 are all 603e cores) */
                .pvr_mask               = 0x7fff0000,
                .pvr_value              = 0x00810000,
index e253a45dcf10d62cb8c18b5faa028d3415c125c9..358cecdc6aef2e1ab8e91778897db3accce3fd11 100644 (file)
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/types.h>
+#include <linux/irq.h>
 
 #include <asm/processor.h>
 #include <asm/machdep.h>
+#include <asm/kexec.h>
 #include <asm/kdump.h>
 #include <asm/lmb.h>
 #include <asm/firmware.h>
@@ -41,6 +43,7 @@
 
 /* This keeps a track of which one is crashing cpu. */
 int crashing_cpu = -1;
+static cpumask_t cpus_in_crash = CPU_MASK_NONE;
 
 static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
                                                               size_t data_len)
@@ -98,34 +101,66 @@ static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
 }
 
 #ifdef CONFIG_SMP
-static atomic_t waiting_for_crash_ipi;
+static atomic_t enter_on_soft_reset = ATOMIC_INIT(0);
 
 void crash_ipi_callback(struct pt_regs *regs)
 {
        int cpu = smp_processor_id();
 
-       if (cpu == crashing_cpu)
-               return;
-
        if (!cpu_online(cpu))
                return;
 
-       if (ppc_md.kexec_cpu_down)
-               ppc_md.kexec_cpu_down(1, 1);
-
        local_irq_disable();
+       if (!cpu_isset(cpu, cpus_in_crash))
+               crash_save_this_cpu(regs, cpu);
+       cpu_set(cpu, cpus_in_crash);
 
-       crash_save_this_cpu(regs, cpu);
-       atomic_dec(&waiting_for_crash_ipi);
+       /*
+        * Entered via soft-reset - could be the kdump
+        * process is invoked using soft-reset or user activated
+        * it if some CPU did not respond to an IPI.
+        * For soft-reset, the secondary CPU can enter this func
+        * twice. 1 - using IPI, and 2. soft-reset.
+        * Tell the kexec CPU that entered via soft-reset and ready
+        * to go down.
+        */
+       if (cpu_isset(cpu, cpus_in_sr)) {
+               cpu_clear(cpu, cpus_in_sr);
+               atomic_inc(&enter_on_soft_reset);
+       }
+
+       /*
+        * Starting the kdump boot.
+        * This barrier is needed to make sure that all CPUs are stopped.
+        * If not, soft-reset will be invoked to bring other CPUs.
+        */
+       while (!cpu_isset(crashing_cpu, cpus_in_crash))
+               cpu_relax();
+
+       if (ppc_md.kexec_cpu_down)
+               ppc_md.kexec_cpu_down(1, 1);
        kexec_smp_wait();
        /* NOTREACHED */
 }
 
-static void crash_kexec_prepare_cpus(void)
+/*
+ * Wait until all CPUs are entered via soft-reset.
+ */
+static void crash_soft_reset_check(int cpu)
+{
+       unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
+
+       cpu_clear(cpu, cpus_in_sr);
+       while (atomic_read(&enter_on_soft_reset) != ncpus)
+               cpu_relax();
+}
+
+
+static void crash_kexec_prepare_cpus(int cpu)
 {
        unsigned int msecs;
 
-       atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+       unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
 
        crash_send_ipi(crash_ipi_callback);
        smp_wmb();
@@ -133,14 +168,13 @@ static void crash_kexec_prepare_cpus(void)
        /*
         * FIXME: Until we will have the way to stop other CPUSs reliabally,
         * the crash CPU will send an IPI and wait for other CPUs to
-        * respond. If not, proceed the kexec boot even though we failed to
-        * capture other CPU states.
+        * respond.
         * Delay of at least 10 seconds.
         */
-       printk(KERN_ALERT "Sending IPI to other cpus...\n");
+       printk(KERN_EMERG "Sending IPI to other cpus...\n");
        msecs = 10000;
-       while ((atomic_read(&waiting_for_crash_ipi) > 0) && (--msecs > 0)) {
-               barrier();
+       while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) {
+               cpu_relax();
                mdelay(1);
        }
 
@@ -149,18 +183,71 @@ static void crash_kexec_prepare_cpus(void)
        /*
         * FIXME: In case if we do not get all CPUs, one possibility: ask the
         * user to do soft reset such that we get all.
-        * IPI handler is already set by the panic cpu initially. Therefore,
-        * all cpus could invoke this handler from die() and the panic CPU
-        * will call machine_kexec() directly from this handler to do
-        * kexec boot.
+        * Soft-reset will be used until better mechanism is implemented.
+        */
+       if (cpus_weight(cpus_in_crash) < ncpus) {
+               printk(KERN_EMERG "done waiting: %d cpu(s) not responding\n",
+                       ncpus - cpus_weight(cpus_in_crash));
+               printk(KERN_EMERG "Activate soft-reset to stop other cpu(s)\n");
+               cpus_in_sr = CPU_MASK_NONE;
+               atomic_set(&enter_on_soft_reset, 0);
+               while (cpus_weight(cpus_in_crash) < ncpus)
+                       cpu_relax();
+       }
+       /*
+        * Make sure all CPUs are entered via soft-reset if the kdump is
+        * invoked using soft-reset.
         */
-       if (atomic_read(&waiting_for_crash_ipi))
-               printk(KERN_ALERT "done waiting: %d cpus not responding\n",
-                       atomic_read(&waiting_for_crash_ipi));
+       if (cpu_isset(cpu, cpus_in_sr))
+               crash_soft_reset_check(cpu);
        /* Leave the IPI callback set */
 }
+
+/*
+ * This function will be called by secondary cpus or by kexec cpu
+ * if soft-reset is activated to stop some CPUs.
+ */
+void crash_kexec_secondary(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+       unsigned long flags;
+       int msecs = 5;
+
+       local_irq_save(flags);
+       /* Wait 5ms if the kexec CPU is not entered yet. */
+       while (crashing_cpu < 0) {
+               if (--msecs < 0) {
+                       /*
+                        * Either kdump image is not loaded or
+                        * kdump process is not started - Probably xmon
+                        * exited using 'x'(exit and recover) or
+                        * kexec_should_crash() failed for all running tasks.
+                        */
+                       cpu_clear(cpu, cpus_in_sr);
+                       local_irq_restore(flags);
+                       return;
+               }
+               mdelay(1);
+               cpu_relax();
+       }
+       if (cpu == crashing_cpu) {
+               /*
+                * Panic CPU will enter this func only via soft-reset.
+                * Wait until all secondary CPUs entered and
+                * then start kexec boot.
+                */
+               crash_soft_reset_check(cpu);
+               cpu_set(crashing_cpu, cpus_in_crash);
+               if (ppc_md.kexec_cpu_down)
+                       ppc_md.kexec_cpu_down(1, 0);
+               machine_kexec(kexec_crash_image);
+               /* NOTREACHED */
+       }
+       crash_ipi_callback(regs);
+}
+
 #else
-static void crash_kexec_prepare_cpus(void)
+static void crash_kexec_prepare_cpus(int cpu)
 {
        /*
         * move the secondarys to us so that we can copy
@@ -171,6 +258,10 @@ static void crash_kexec_prepare_cpus(void)
        smp_release_cpus();
 }
 
+void crash_kexec_secondary(struct pt_regs *regs)
+{
+       cpus_in_sr = CPU_MASK_NONE;
+}
 #endif
 
 void default_machine_crash_shutdown(struct pt_regs *regs)
@@ -190,23 +281,23 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
        local_irq_disable();
 
        for_each_irq(irq) {
-               struct irq_desc *desc = irq_descp(irq);
+               struct irq_desc *desc = irq_desc + irq;
 
                if (desc->status & IRQ_INPROGRESS)
-                       desc->handler->end(irq);
+                       desc->chip->end(irq);
 
                if (!(desc->status & IRQ_DISABLED))
-                       desc->handler->disable(irq);
+                       desc->chip->disable(irq);
        }
 
-       if (ppc_md.kexec_cpu_down)
-               ppc_md.kexec_cpu_down(1, 0);
-
        /*
         * Make a note of crashing cpu. Will be used in machine_kexec
         * such that another IPI will not be sent.
         */
        crashing_cpu = smp_processor_id();
-       crash_kexec_prepare_cpus();
        crash_save_this_cpu(regs, crashing_cpu);
+       crash_kexec_prepare_cpus(crashing_cpu);
+       cpu_set(crashing_cpu, cpus_in_crash);
+       if (ppc_md.kexec_cpu_down)
+               ppc_md.kexec_cpu_down(1, 0);
 }
index 831acbdf2592508734c45b3ab35b2a61482b5172..8cfd040d1f50c07211eca77ce4694d1cabf0f12e 100644 (file)
@@ -85,34 +85,6 @@ END_FTR_SECTION(0, 1)
        /* Catch branch to 0 in real mode */
        trap
 
-#ifdef CONFIG_PPC_ISERIES
-       /*
-        * At offset 0x20, there is a pointer to iSeries LPAR data.
-        * This is required by the hypervisor
-        */
-       . = 0x20
-       .llong hvReleaseData-KERNELBASE
-
-       /*
-        * At offset 0x28 and 0x30 are offsets to the mschunks_map
-        * array (used by the iSeries LPAR debugger to do translation
-        * between physical addresses and absolute addresses) and
-        * to the pidhash table (also used by the debugger)
-        */
-       .llong mschunks_map-KERNELBASE
-       .llong 0        /* pidhash-KERNELBASE SFRXXX */
-
-       /* Offset 0x38 - Pointer to start of embedded System.map */
-       .globl  embedded_sysmap_start
-embedded_sysmap_start:
-       .llong  0
-       /* Offset 0x40 - Pointer to end of embedded System.map */
-       .globl  embedded_sysmap_end
-embedded_sysmap_end:
-       .llong  0
-
-#endif /* CONFIG_PPC_ISERIES */
-
        /* Secondary processors spin on this value until it goes to 1. */
        .globl  __secondary_hold_spinloop
 __secondary_hold_spinloop:
@@ -124,6 +96,15 @@ __secondary_hold_spinloop:
 __secondary_hold_acknowledge:
        .llong  0x0
 
+#ifdef CONFIG_PPC_ISERIES
+       /*
+        * At offset 0x20, there is a pointer to iSeries LPAR data.
+        * This is required by the hypervisor
+        */
+       . = 0x20
+       .llong hvReleaseData-KERNELBASE
+#endif /* CONFIG_PPC_ISERIES */
+
        . = 0x60
 /*
  * The following code is used on pSeries to hold secondary processors
@@ -1602,9 +1583,6 @@ _GLOBAL(__start_initialization_multiplatform)
        /* Setup some critical 970 SPRs before switching MMU off */
        bl      .__970_cpu_preinit
 
-       /* cpu # */
-       li      r24,0
-
        /* Switch off MMU if not already */
        LOAD_REG_IMMEDIATE(r4, .__after_prom_start - KERNELBASE)
        add     r4,r4,r30
@@ -1683,6 +1661,9 @@ _STATIC(__after_prom_start)
                                        /*   i.e. where we are running   */
                                        /*      the source addr          */
 
+       cmpdi   r4,0                    /* In some cases the loader may  */
+       beq     .start_here_multiplatform /* have already put us at zero */
+                                       /* so we can skip the copy.      */
        LOAD_REG_IMMEDIATE(r5,copy_to_here) /* # bytes of memory to copy */
        sub     r5,r5,r27
 
@@ -1962,14 +1943,6 @@ _STATIC(start_here_common)
        li      r3,0
        bl      .do_cpu_ftr_fixups
 
-       LOAD_REG_IMMEDIATE(r26, boot_cpuid)
-       lwz     r26,0(r26)
-
-       LOAD_REG_IMMEDIATE(r24, paca)   /* Get base vaddr of paca array  */
-       mulli   r13,r26,PACA_SIZE       /* Calculate vaddr of right paca */
-       add     r13,r13,r24             /* for this processor.           */
-       mtspr   SPRN_SPRG3,r13
-
        /* ptr to current */
        LOAD_REG_IMMEDIATE(r4, init_task)
        std     r4,PACACURRENT(r13)
@@ -1995,17 +1968,6 @@ _STATIC(start_here_common)
        /* Not reached */
        BUG_OPCODE
 
-/* Put the paca pointer into r13 and SPRG3 */
-_GLOBAL(setup_boot_paca)
-       LOAD_REG_IMMEDIATE(r3, boot_cpuid)
-       lwz     r3,0(r3)
-       LOAD_REG_IMMEDIATE(r4, paca)    /* Get base vaddr of paca array  */
-       mulli   r3,r3,PACA_SIZE         /* Calculate vaddr of right paca */
-       add     r13,r3,r4               /* for this processor.           */
-       mtspr   SPRN_SPRG3,r13
-
-       blr
-
 /*
  * We put a few things here that have to be page-aligned.
  * This stuff goes at the beginning of the bss, which is page-aligned.
index 7cb77c20fc5d0a5c979eade8dbe1ea86ecfa4bad..3d677ac996592d1cb4c15462499c41b6e0e1ecf0 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/iommu.h>
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
+#include <asm/kdump.h>
 
 #define DBG(...)
 
@@ -440,8 +441,37 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
        tbl->it_largehint = tbl->it_halfpoint;
        spin_lock_init(&tbl->it_lock);
 
+#ifdef CONFIG_CRASH_DUMP
+       if (ppc_md.tce_get) {
+               unsigned long index, tceval;
+               unsigned long tcecount = 0;
+
+               /*
+                * Reserve the existing mappings left by the first kernel.
+                */
+               for (index = 0; index < tbl->it_size; index++) {
+                       tceval = ppc_md.tce_get(tbl, index + tbl->it_offset);
+                       /*
+                        * Freed TCE entry contains 0x7fffffffffffffff on JS20
+                        */
+                       if (tceval && (tceval != 0x7fffffffffffffffUL)) {
+                               __set_bit(index, tbl->it_map);
+                               tcecount++;
+                       }
+               }
+               if ((tbl->it_size - tcecount) < KDUMP_MIN_TCE_ENTRIES) {
+                       printk(KERN_WARNING "TCE table is full; ");
+                       printk(KERN_WARNING "freeing %d entries for the kdump boot\n",
+                               KDUMP_MIN_TCE_ENTRIES);
+                       for (index = tbl->it_size - KDUMP_MIN_TCE_ENTRIES;
+                               index < tbl->it_size; index++)
+                               __clear_bit(index, tbl->it_map);
+               }
+       }
+#else
        /* Clear the hardware table in case firmware left allocations in it */
        ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
+#endif
 
        if (!welcomed) {
                printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
index 40d4c14fde8fa2ae3333062786688584b3387757..24f6050aa4abb2d13a873659e737ae13442409bc 100644 (file)
@@ -120,8 +120,8 @@ int show_interrupts(struct seq_file *p, void *v)
 #else
                seq_printf(p, "%10u ", kstat_irqs(i));
 #endif /* CONFIG_SMP */
-               if (desc->handler)
-                       seq_printf(p, " %s ", desc->handler->typename);
+               if (desc->chip)
+                       seq_printf(p, " %s ", desc->chip->typename);
                else
                        seq_puts(p, "  None      ");
                seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge  ");
@@ -164,13 +164,13 @@ void fixup_irqs(cpumask_t map)
                if (irq_desc[irq].status & IRQ_PER_CPU)
                        continue;
 
-               cpus_and(mask, irq_affinity[irq], map);
+               cpus_and(mask, irq_desc[irq].affinity, map);
                if (any_online_cpu(mask) == NR_CPUS) {
                        printk("Breaking affinity for irq %i\n", irq);
                        mask = map;
                }
-               if (irq_desc[irq].handler->set_affinity)
-                       irq_desc[irq].handler->set_affinity(irq, mask);
+               if (irq_desc[irq].chip->set_affinity)
+                       irq_desc[irq].chip->set_affinity(irq, mask);
                else if (irq_desc[irq].action && !(warned++))
                        printk("Cannot set affinity for irq %i\n", irq);
        }
index 6e67b5b49ba1aedaa44a818835e396a0701a1185..3a9b78d0354205d27a92bc1fab94235ea12f46ee 100644 (file)
@@ -302,6 +302,17 @@ void __init find_legacy_serial_ports(void)
                of_node_put(isa);
        }
 
+       /* First fill our array with tsi-bridge ports */
+       for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16550")) != NULL;) {
+               struct device_node *tsi = of_get_parent(np);
+               if (tsi && !strcmp(tsi->type, "tsi-bridge")) {
+                       index = add_legacy_soc_port(np, np);
+                       if (index >= 0 && np == stdout)
+                               legacy_serial_console = index;
+               }
+               of_node_put(tsi);
+       }
+
 #ifdef CONFIG_PCI
        /* Next, try to locate PCI ports */
        for (np = NULL; (np = of_find_all_nodes(np));) {
index c02deaab26c78d241f15b6c805a38309fdfe52b7..73edc3c16137f532a84754536da5509575d3b927 100644 (file)
 static struct proc_dir_entry *proc_ppc64_lparcfg;
 #define LPARCFG_BUFF_SIZE 4096
 
-#ifdef CONFIG_PPC_ISERIES
-
 /*
- * For iSeries legacy systems, the PPA purr function is available from the
- * emulated_time_base field in the paca.
+ * Track sum of all purrs across all processors. This is used to further
+ * calculate usage values by different applications
  */
 static unsigned long get_purr(void)
 {
@@ -57,48 +55,31 @@ static unsigned long get_purr(void)
        int cpu;
 
        for_each_possible_cpu(cpu) {
-               sum_purr += lppaca[cpu].emulated_time_base;
+               if (firmware_has_feature(FW_FEATURE_ISERIES))
+                       sum_purr += lppaca[cpu].emulated_time_base;
+               else {
+                       struct cpu_usage *cu;
 
-#ifdef PURR_DEBUG
-               printk(KERN_INFO "get_purr for cpu (%d) has value (%ld) \n",
-                       cpu, lppaca[cpu].emulated_time_base);
-#endif
+                       cu = &per_cpu(cpu_usage_array, cpu);
+                       sum_purr += cu->current_tb;
+               }
        }
        return sum_purr;
 }
 
-#define lparcfg_write NULL
+#ifdef CONFIG_PPC_ISERIES
 
 /*
  * Methods used to fetch LPAR data when running on an iSeries platform.
  */
-static int lparcfg_data(struct seq_file *m, void *v)
+static int iseries_lparcfg_data(struct seq_file *m, void *v)
 {
-       unsigned long pool_id, lp_index;
+       unsigned long pool_id;
        int shared, entitled_capacity, max_entitled_capacity;
        int processors, max_processors;
        unsigned long purr = get_purr();
 
-       seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
-
        shared = (int)(get_lppaca()->shared_proc);
-       seq_printf(m, "serial_number=%c%c%c%c%c%c%c\n",
-                  e2a(xItExtVpdPanel.mfgID[2]),
-                  e2a(xItExtVpdPanel.mfgID[3]),
-                  e2a(xItExtVpdPanel.systemSerial[1]),
-                  e2a(xItExtVpdPanel.systemSerial[2]),
-                  e2a(xItExtVpdPanel.systemSerial[3]),
-                  e2a(xItExtVpdPanel.systemSerial[4]),
-                  e2a(xItExtVpdPanel.systemSerial[5]));
-
-       seq_printf(m, "system_type=%c%c%c%c\n",
-                  e2a(xItExtVpdPanel.machineType[0]),
-                  e2a(xItExtVpdPanel.machineType[1]),
-                  e2a(xItExtVpdPanel.machineType[2]),
-                  e2a(xItExtVpdPanel.machineType[3]));
-
-       lp_index = HvLpConfig_getLpIndex();
-       seq_printf(m, "partition_id=%d\n", (int)lp_index);
 
        seq_printf(m, "system_active_processors=%d\n",
                   (int)HvLpConfig_getSystemPhysicalProcessors());
@@ -137,6 +118,14 @@ static int lparcfg_data(struct seq_file *m, void *v)
 
        return 0;
 }
+
+#else                          /* CONFIG_PPC_ISERIES */
+
+static int iseries_lparcfg_data(struct seq_file *m, void *v)
+{
+       return 0;
+}
+
 #endif                         /* CONFIG_PPC_ISERIES */
 
 #ifdef CONFIG_PPC_PSERIES
@@ -213,22 +202,6 @@ static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs)
                log_plpar_hcall_return(rc, "H_PIC");
 }
 
-/* Track sum of all purrs across all processors. This is used to further */
-/* calculate usage values by different applications                       */
-
-static unsigned long get_purr(void)
-{
-       unsigned long sum_purr = 0;
-       int cpu;
-       struct cpu_usage *cu;
-
-       for_each_possible_cpu(cpu) {
-               cu = &per_cpu(cpu_usage_array, cpu);
-               sum_purr += cu->current_tb;
-       }
-       return sum_purr;
-}
-
 #define SPLPAR_CHARACTERISTICS_TOKEN 20
 #define SPLPAR_MAXLENGTH 1026*(sizeof(char))
 
@@ -333,35 +306,13 @@ static int lparcfg_count_active_processors(void)
        return count;
 }
 
-static int lparcfg_data(struct seq_file *m, void *v)
+static int pseries_lparcfg_data(struct seq_file *m, void *v)
 {
        int partition_potential_processors;
        int partition_active_processors;
-       struct device_node *rootdn;
-       const char *model = "";
-       const char *system_id = "";
-       unsigned int *lp_index_ptr, lp_index = 0;
        struct device_node *rtas_node;
        int *lrdrp = NULL;
 
-       rootdn = find_path_device("/");
-       if (rootdn) {
-               model = get_property(rootdn, "model", NULL);
-               system_id = get_property(rootdn, "system-id", NULL);
-               lp_index_ptr = (unsigned int *)
-                   get_property(rootdn, "ibm,partition-no", NULL);
-               if (lp_index_ptr)
-                       lp_index = *lp_index_ptr;
-       }
-
-       seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
-
-       seq_printf(m, "serial_number=%s\n", system_id);
-
-       seq_printf(m, "system_type=%s\n", model);
-
-       seq_printf(m, "partition_id=%d\n", (int)lp_index);
-
        rtas_node = find_path_device("/rtas");
        if (rtas_node)
                lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity",
@@ -549,8 +500,61 @@ out:
        return retval;
 }
 
+#else                          /* CONFIG_PPC_PSERIES */
+
+static int pseries_lparcfg_data(struct seq_file *m, void *v)
+{
+       return 0;
+}
+
+static ssize_t lparcfg_write(struct file *file, const char __user * buf,
+                            size_t count, loff_t * off)
+{
+       return count;
+}
+
 #endif                         /* CONFIG_PPC_PSERIES */
 
+static int lparcfg_data(struct seq_file *m, void *v)
+{
+       struct device_node *rootdn;
+       const char *model = "";
+       const char *system_id = "";
+       const char *tmp;
+       unsigned int *lp_index_ptr, lp_index = 0;
+
+       seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
+
+       rootdn = find_path_device("/");
+       if (rootdn) {
+               tmp = get_property(rootdn, "model", NULL);
+               if (tmp) {
+                       model = tmp;
+                       /* Skip "IBM," - see platforms/iseries/dt.c */
+                       if (firmware_has_feature(FW_FEATURE_ISERIES))
+                               model += 4;
+               }
+               tmp = get_property(rootdn, "system-id", NULL);
+               if (tmp) {
+                       system_id = tmp;
+                       /* Skip "IBM," - see platforms/iseries/dt.c */
+                       if (firmware_has_feature(FW_FEATURE_ISERIES))
+                               system_id += 4;
+               }
+               lp_index_ptr = (unsigned int *)
+                       get_property(rootdn, "ibm,partition-no", NULL);
+               if (lp_index_ptr)
+                       lp_index = *lp_index_ptr;
+       }
+       seq_printf(m, "serial_number=%s\n", system_id);
+       seq_printf(m, "system_type=%s\n", model);
+       seq_printf(m, "partition_id=%d\n", (int)lp_index);
+
+       if (firmware_has_feature(FW_FEATURE_ISERIES))
+               return iseries_lparcfg_data(m, v);
+       return pseries_lparcfg_data(m, v);
+}
+
 static int lparcfg_open(struct inode *inode, struct file *file)
 {
        return single_open(file, lparcfg_data, NULL);
@@ -569,7 +573,8 @@ int __init lparcfg_init(void)
        mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
 
        /* Allow writing if we have FW_FEATURE_SPLPAR */
-       if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+       if (firmware_has_feature(FW_FEATURE_SPLPAR) &&
+                       !firmware_has_feature(FW_FEATURE_ISERIES)) {
                lparcfg_fops.write = lparcfg_write;
                mode |= S_IWUSR;
        }
index a8fa04ef27cd79597a65842f8e9b380d8eb3d828..b438d45a068c6b0dd621b0f51520f9478b729539 100644 (file)
@@ -378,11 +378,13 @@ static void __init export_crashk_values(void)
        of_node_put(node);
 }
 
-void __init kexec_setup(void)
+static int __init kexec_setup(void)
 {
        export_htab_values();
        export_crashk_values();
+       return 0;
 }
+__initcall(kexec_setup);
 
 static int __init early_parse_crashk(char *p)
 {
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S
new file mode 100644 (file)
index 0000000..fc23040
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * This file contains miscellaneous low-level functions.
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
+ * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <asm/ppc_asm.h>
+
+       .text
+
+#ifdef CONFIG_PPC64
+#define IN_SYNC                twi     0,r5,0; isync
+#define EIEIO_32
+#define SYNC_64                sync
+#else /* CONFIG_PPC32 */
+#define IN_SYNC
+#define EIEIO_32       eieio
+#define SYNC_64
+#endif
+/*
+ * Returns (address we are running at) - (address we were linked at)
+ * for use before the text and data are mapped to KERNELBASE.
+ */
+
+_GLOBAL(reloc_offset)
+       mflr    r0
+       bl      1f
+1:     mflr    r3
+       LOAD_REG_IMMEDIATE(r4,1b)
+       subf    r3,r4,r3
+       mtlr    r0
+       blr
+
+/*
+ * add_reloc_offset(x) returns x + reloc_offset().
+ */
+_GLOBAL(add_reloc_offset)
+       mflr    r0
+       bl      1f
+1:     mflr    r5
+       LOAD_REG_IMMEDIATE(r4,1b)
+       subf    r5,r4,r5
+       add     r3,r3,r5
+       mtlr    r0
+       blr
+
+/*
+ * I/O string operations
+ *
+ * insb(port, buf, len)
+ * outsb(port, buf, len)
+ * insw(port, buf, len)
+ * outsw(port, buf, len)
+ * insl(port, buf, len)
+ * outsl(port, buf, len)
+ * insw_ns(port, buf, len)
+ * outsw_ns(port, buf, len)
+ * insl_ns(port, buf, len)
+ * outsl_ns(port, buf, len)
+ *
+ * The *_ns versions don't do byte-swapping.
+ */
+_GLOBAL(_insb)
+       cmpwi   0,r5,0
+       mtctr   r5
+       subi    r4,r4,1
+       blelr-
+00:    lbz     r5,0(r3)
+       eieio
+       stbu    r5,1(r4)
+       bdnz    00b
+       IN_SYNC
+       blr
+
+_GLOBAL(_outsb)
+       cmpwi   0,r5,0
+       mtctr   r5
+       subi    r4,r4,1
+       blelr-
+00:    lbzu    r5,1(r4)
+       stb     r5,0(r3)
+       EIEIO_32
+       bdnz    00b
+       SYNC_64
+       blr
+
+_GLOBAL(_insw)
+       cmpwi   0,r5,0
+       mtctr   r5
+       subi    r4,r4,2
+       blelr-
+00:    lhbrx   r5,0,r3
+       eieio
+       sthu    r5,2(r4)
+       bdnz    00b
+       IN_SYNC
+       blr
+
+_GLOBAL(_outsw)
+       cmpwi   0,r5,0
+       mtctr   r5
+       subi    r4,r4,2
+       blelr-
+00:    lhzu    r5,2(r4)
+       EIEIO_32
+       sthbrx  r5,0,r3
+       bdnz    00b
+       SYNC_64
+       blr
+
+_GLOBAL(_insl)
+       cmpwi   0,r5,0
+       mtctr   r5
+       subi    r4,r4,4
+       blelr-
+00:    lwbrx   r5,0,r3
+       eieio
+       stwu    r5,4(r4)
+       bdnz    00b
+       IN_SYNC
+       blr
+
+_GLOBAL(_outsl)
+       cmpwi   0,r5,0
+       mtctr   r5
+       subi    r4,r4,4
+       blelr-
+00:    lwzu    r5,4(r4)
+       stwbrx  r5,0,r3
+       EIEIO_32
+       bdnz    00b
+       SYNC_64
+       blr
+
+#ifdef CONFIG_PPC32
+_GLOBAL(__ide_mm_insw)
+#endif
+_GLOBAL(_insw_ns)
+       cmpwi   0,r5,0
+       mtctr   r5
+       subi    r4,r4,2
+       blelr-
+00:    lhz     r5,0(r3)
+       eieio
+       sthu    r5,2(r4)
+       bdnz    00b
+       IN_SYNC
+       blr
+
+#ifdef CONFIG_PPC32
+_GLOBAL(__ide_mm_outsw)
+#endif
+_GLOBAL(_outsw_ns)
+       cmpwi   0,r5,0
+       mtctr   r5
+       subi    r4,r4,2
+       blelr-
+00:    lhzu    r5,2(r4)
+       sth     r5,0(r3)
+       EIEIO_32
+       bdnz    00b
+       SYNC_64
+       blr
+
+#ifdef CONFIG_PPC32
+_GLOBAL(__ide_mm_insl)
+#endif
+_GLOBAL(_insl_ns)
+       cmpwi   0,r5,0
+       mtctr   r5
+       subi    r4,r4,4
+       blelr-
+00:    lwz     r5,0(r3)
+       eieio
+       stwu    r5,4(r4)
+       bdnz    00b
+       IN_SYNC
+       blr
+
+#ifdef CONFIG_PPC32
+_GLOBAL(__ide_mm_outsl)
+#endif
+_GLOBAL(_outsl_ns)
+       cmpwi   0,r5,0
+       mtctr   r5
+       subi    r4,r4,4
+       blelr-
+00:    lwzu    r5,4(r4)
+       stw     r5,0(r3)
+       EIEIO_32
+       bdnz    00b
+       SYNC_64
+       blr
+
index 01d3916c4cb13f6dc01b431328f3f2a1a49e4007..c74774e2175d9075a8a60a9b0636f18bf5fddc66 100644 (file)
@@ -60,32 +60,6 @@ _GLOBAL(mulhdu)
        addze   r3,r3
        blr
 
-/*
- * Returns (address we're running at) - (address we were linked at)
- * for use before the text and data are mapped to KERNELBASE.
- */
-_GLOBAL(reloc_offset)
-       mflr    r0
-       bl      1f
-1:     mflr    r3
-       LOAD_REG_IMMEDIATE(r4,1b)
-       subf    r3,r4,r3
-       mtlr    r0
-       blr
-
-/*
- * add_reloc_offset(x) returns x + reloc_offset().
- */
-_GLOBAL(add_reloc_offset)
-       mflr    r0
-       bl      1f
-1:     mflr    r5
-       LOAD_REG_IMMEDIATE(r4,1b)
-       subf    r5,r4,r5
-       add     r3,r3,r5
-       mtlr    r0
-       blr
-
 /*
  * sub_reloc_offset(x) returns x - reloc_offset().
  */
@@ -780,136 +754,6 @@ _GLOBAL(atomic_set_mask)
        bne-    10b
        blr
 
-/*
- * I/O string operations
- *
- * insb(port, buf, len)
- * outsb(port, buf, len)
- * insw(port, buf, len)
- * outsw(port, buf, len)
- * insl(port, buf, len)
- * outsl(port, buf, len)
- * insw_ns(port, buf, len)
- * outsw_ns(port, buf, len)
- * insl_ns(port, buf, len)
- * outsl_ns(port, buf, len)
- *
- * The *_ns versions don't do byte-swapping.
- */
-_GLOBAL(_insb)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,1
-       blelr-
-00:    lbz     r5,0(r3)
-       eieio
-       stbu    r5,1(r4)
-       bdnz    00b
-       blr
-
-_GLOBAL(_outsb)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,1
-       blelr-
-00:    lbzu    r5,1(r4)
-       stb     r5,0(r3)
-       eieio
-       bdnz    00b
-       blr
-
-_GLOBAL(_insw)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,2
-       blelr-
-00:    lhbrx   r5,0,r3
-       eieio
-       sthu    r5,2(r4)
-       bdnz    00b
-       blr
-
-_GLOBAL(_outsw)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,2
-       blelr-
-00:    lhzu    r5,2(r4)
-       eieio
-       sthbrx  r5,0,r3
-       bdnz    00b
-       blr
-
-_GLOBAL(_insl)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,4
-       blelr-
-00:    lwbrx   r5,0,r3
-       eieio
-       stwu    r5,4(r4)
-       bdnz    00b
-       blr
-
-_GLOBAL(_outsl)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,4
-       blelr-
-00:    lwzu    r5,4(r4)
-       stwbrx  r5,0,r3
-       eieio
-       bdnz    00b
-       blr
-
-_GLOBAL(__ide_mm_insw)
-_GLOBAL(_insw_ns)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,2
-       blelr-
-00:    lhz     r5,0(r3)
-       eieio
-       sthu    r5,2(r4)
-       bdnz    00b
-       blr
-
-_GLOBAL(__ide_mm_outsw)
-_GLOBAL(_outsw_ns)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,2
-       blelr-
-00:    lhzu    r5,2(r4)
-       sth     r5,0(r3)
-       eieio
-       bdnz    00b
-       blr
-
-_GLOBAL(__ide_mm_insl)
-_GLOBAL(_insl_ns)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,4
-       blelr-
-00:    lwz     r5,0(r3)
-       eieio
-       stwu    r5,4(r4)
-       bdnz    00b
-       blr
-
-_GLOBAL(__ide_mm_outsl)
-_GLOBAL(_outsl_ns)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,4
-       blelr-
-00:    lwzu    r5,4(r4)
-       stw     r5,0(r3)
-       eieio
-       bdnz    00b
-       blr
-
 /*
  * Extended precision shifts.
  *
index e8883d42c43c16c2d237d9cf81ea3a34a8105bd8..580891cb8ccb68766e4f5a28534eb29d81edea36 100644 (file)
@@ -1,14 +1,12 @@
 /*
- *  arch/powerpc/kernel/misc64.S
- *
  * This file contains miscellaneous low-level functions.
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
  * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
  * and Paul Mackerras.
  * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
- * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) 
- * 
+ * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
 
        .text
 
-/*
- * Returns (address we are running at) - (address we were linked at)
- * for use before the text and data are mapped to KERNELBASE.
- */
-
-_GLOBAL(reloc_offset)
-       mflr    r0
-       bl      1f
-1:     mflr    r3
-       LOAD_REG_IMMEDIATE(r4,1b)
-       subf    r3,r4,r3
-       mtlr    r0
-       blr
-
-/*
- * add_reloc_offset(x) returns x + reloc_offset().
- */
-_GLOBAL(add_reloc_offset)
-       mflr    r0
-       bl      1f
-1:     mflr    r5
-       LOAD_REG_IMMEDIATE(r4,1b)
-       subf    r5,r4,r5
-       add     r3,r3,r5
-       mtlr    r0
-       blr
-
 _GLOBAL(get_msr)
        mfmsr   r3
        blr
 
-_GLOBAL(get_dar)
-       mfdar   r3
-       blr
-
 _GLOBAL(get_srr0)
        mfsrr0  r3
        blr
@@ -72,10 +39,6 @@ _GLOBAL(get_srr0)
 _GLOBAL(get_srr1)
        mfsrr1  r3
        blr
-       
-_GLOBAL(get_sp)
-       mr      r3,r1
-       blr
 
 #ifdef CONFIG_IRQSTACKS
 _GLOBAL(call_do_softirq)
@@ -101,48 +64,6 @@ _GLOBAL(call___do_IRQ)
        blr
 #endif /* CONFIG_IRQSTACKS */
 
-       /*
- * To be called by C code which needs to do some operations with MMU
- * disabled. Note that interrupts have to be disabled by the caller
- * prior to calling us. The code called _MUST_ be in the RMO of course
- * and part of the linear mapping as we don't attempt to translate the
- * stack pointer at all. The function is called with the stack switched
- * to this CPU emergency stack
- *
- * prototype is void *call_with_mmu_off(void *func, void *data);
- *
- * the called function is expected to be of the form
- *
- * void *called(void *data); 
- */
-_GLOBAL(call_with_mmu_off)
-       mflr    r0                      /* get link, save it on stackframe */
-       std     r0,16(r1)
-       mr      r1,r5                   /* save old stack ptr */
-       ld      r1,PACAEMERGSP(r13)     /* get emerg. stack */
-       subi    r1,r1,STACK_FRAME_OVERHEAD
-       std     r0,16(r1)               /* save link on emerg. stack */
-       std     r5,0(r1)                /* save old stack ptr in backchain */
-       ld      r3,0(r3)                /* get to real function ptr (assume same TOC) */
-       bl      2f                      /* we need LR to return, continue at label 2 */
-
-       ld      r0,16(r1)               /* we return here from the call, get LR and */
-       ld      r1,0(r1)                /* .. old stack ptr */
-       mtspr   SPRN_SRR0,r0            /* and get back to virtual mode with these */
-       mfmsr   r4
-       ori     r4,r4,MSR_IR|MSR_DR
-       mtspr   SPRN_SRR1,r4
-       rfid
-
-2:     mtspr   SPRN_SRR0,r3            /* coming from above, enter real mode */
-       mr      r3,r4                   /* get parameter */
-       mfmsr   r0
-       ori     r0,r0,MSR_IR|MSR_DR
-       xori    r0,r0,MSR_IR|MSR_DR
-       mtspr   SPRN_SRR1,r0
-       rfid
-
-
        .section        ".toc","aw"
 PPC64_CACHES:
        .tc             ppc64_caches[TC],ppc64_caches
@@ -323,144 +244,6 @@ _GLOBAL(__flush_dcache_icache)
        bdnz    1b
        isync
        blr
-       
-/*
- * I/O string operations
- *
- * insb(port, buf, len)
- * outsb(port, buf, len)
- * insw(port, buf, len)
- * outsw(port, buf, len)
- * insl(port, buf, len)
- * outsl(port, buf, len)
- * insw_ns(port, buf, len)
- * outsw_ns(port, buf, len)
- * insl_ns(port, buf, len)
- * outsl_ns(port, buf, len)
- *
- * The *_ns versions don't do byte-swapping.
- */
-_GLOBAL(_insb)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,1
-       blelr-
-00:    lbz     r5,0(r3)
-       eieio
-       stbu    r5,1(r4)
-       bdnz    00b
-       twi     0,r5,0
-       isync
-       blr
-
-_GLOBAL(_outsb)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,1
-       blelr-
-00:    lbzu    r5,1(r4)
-       stb     r5,0(r3)
-       bdnz    00b
-       sync
-       blr     
-
-_GLOBAL(_insw)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,2
-       blelr-
-00:    lhbrx   r5,0,r3
-       eieio
-       sthu    r5,2(r4)
-       bdnz    00b
-       twi     0,r5,0
-       isync
-       blr
-
-_GLOBAL(_outsw)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,2
-       blelr-
-00:    lhzu    r5,2(r4)
-       sthbrx  r5,0,r3 
-       bdnz    00b
-       sync
-       blr     
-
-_GLOBAL(_insl)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,4
-       blelr-
-00:    lwbrx   r5,0,r3
-       eieio
-       stwu    r5,4(r4)
-       bdnz    00b
-       twi     0,r5,0
-       isync
-       blr
-
-_GLOBAL(_outsl)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,4
-       blelr-
-00:    lwzu    r5,4(r4)
-       stwbrx  r5,0,r3
-       bdnz    00b
-       sync
-       blr     
-
-/* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */
-_GLOBAL(_insw_ns)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,2
-       blelr-
-00:    lhz     r5,0(r3)
-       eieio
-       sthu    r5,2(r4)
-       bdnz    00b
-       twi     0,r5,0
-       isync
-       blr
-
-/* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */
-_GLOBAL(_outsw_ns)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,2
-       blelr-
-00:    lhzu    r5,2(r4)
-       sth     r5,0(r3)
-       bdnz    00b
-       sync
-       blr     
-
-_GLOBAL(_insl_ns)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,4
-       blelr-
-00:    lwz     r5,0(r3)
-       eieio
-       stwu    r5,4(r4)
-       bdnz    00b
-       twi     0,r5,0
-       isync
-       blr
-
-_GLOBAL(_outsl_ns)
-       cmpwi   0,r5,0
-       mtctr   r5
-       subi    r4,r4,4
-       blelr-
-00:    lwzu    r5,4(r4)
-       stw     r5,0(r3)
-       bdnz    00b
-       sync
-       blr     
 
 /*
  * identify_cpu and calls setup_cpu
@@ -605,6 +388,7 @@ _GLOBAL(real_writeb)
        blr
 #endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
 
+#ifdef CONFIG_CPU_FREQ_PMAC64
 /*
  * SCOM access functions for 970 (FX only for now)
  *
@@ -673,6 +457,7 @@ _GLOBAL(scom970_write)
        /* restore interrupts */
        mtmsrd  r5,1
        blr
+#endif /* CONFIG_CPU_FREQ_PMAC64 */
 
 
 /*
index f505a8827e3ea67c81b0329b2af390b5ddf4e657..a0bb354c1c08154e070ea032b290b0e5a07d35d8 100644 (file)
@@ -16,7 +16,6 @@
 #include <asm/ptrace.h>
 #include <asm/page.h>
 #include <asm/lppaca.h>
-#include <asm/iseries/it_lp_queue.h>
 #include <asm/iseries/it_lp_reg_save.h>
 #include <asm/paca.h>
 
index b5431ccf1147ae551c763b0fd360d3857c4ee00b..8474355a1a4f46d8a9e1df29a2ad403fc847713a 100644 (file)
@@ -99,7 +99,7 @@ pcibios_fixup_resources(struct pci_dev *dev)
                if (!res->flags)
                        continue;
                if (res->end == 0xffffffff) {
-                       DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n",
+                       DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n",
                            pci_name(dev), i, res->start, res->end);
                        res->end -= res->start;
                        res->start = 0;
@@ -117,7 +117,7 @@ pcibios_fixup_resources(struct pci_dev *dev)
                        res->start += offset;
                        res->end += offset;
 #ifdef DEBUG
-                       printk("Fixup res %d (%lx) of dev %s: %lx -> %lx\n",
+                       printk("Fixup res %d (%lx) of dev %s: %llx -> %llx\n",
                               i, res->flags, pci_name(dev),
                               res->start - offset, res->start);
 #endif
@@ -173,18 +173,18 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
  * but we want to try to avoid allocating at 0x2900-0x2bff
  * which might have be mirrored at 0x0100-0x03ff..
  */
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size,
-                      unsigned long align)
+void pcibios_align_resource(void *data, struct resource *res,
+                               resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
 
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (size > 0x100) {
                        printk(KERN_ERR "PCI: I/O Region %s/%d too large"
-                              " (%ld bytes)\n", pci_name(dev),
-                              dev->resource - res, size);
+                              " (%lld bytes)\n", pci_name(dev),
+                              dev->resource - res, (unsigned long long)size);
                }
 
                if (start & 0x300) {
@@ -255,8 +255,8 @@ pcibios_allocate_bus_resources(struct list_head *bus_list)
                                }
                        }
 
-                       DBG("PCI: bridge rsrc %lx..%lx (%lx), parent %p\n",
-                           res->start, res->end, res->flags, pr);
+                       DBG("PCI: bridge rsrc %llx..%llx (%lx), parent %p\n",
+                               res->start, res->end, res->flags, pr);
                        if (pr) {
                                if (request_resource(pr, res) == 0)
                                        continue;
@@ -306,7 +306,7 @@ reparent_resources(struct resource *parent, struct resource *res)
        *pp = NULL;
        for (p = res->child; p != NULL; p = p->sibling) {
                p->parent = res;
-               DBG(KERN_INFO "PCI: reparented %s [%lx..%lx] under %s\n",
+               DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n",
                    p->name, p->start, p->end, res->name);
        }
        return 0;
@@ -362,13 +362,14 @@ pci_relocate_bridge_resource(struct pci_bus *bus, int i)
                try = conflict->start - 1;
        }
        if (request_resource(pr, res)) {
-               DBG(KERN_ERR "PCI: huh? couldn't move to %lx..%lx\n",
+               DBG(KERN_ERR "PCI: huh? couldn't move to %llx..%llx\n",
                    res->start, res->end);
                return -1;              /* "can't happen" */
        }
        update_bridge_base(bus, i);
-       printk(KERN_INFO "PCI: bridge %d resource %d moved to %lx..%lx\n",
-              bus->number, i, res->start, res->end);
+       printk(KERN_INFO "PCI: bridge %d resource %d moved to %llx..%llx\n",
+              bus->number, i, (unsigned long long)res->start,
+              (unsigned long long)res->end);
        return 0;
 }
 
@@ -479,14 +480,14 @@ static inline void alloc_resource(struct pci_dev *dev, int idx)
 {
        struct resource *pr, *r = &dev->resource[idx];
 
-       DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx)\n",
+       DBG("PCI:%s: Resource %d: %016llx-%016llx (f=%lx)\n",
            pci_name(dev), idx, r->start, r->end, r->flags);
        pr = pci_find_parent_resource(dev, r);
        if (!pr || request_resource(pr, r) < 0) {
                printk(KERN_ERR "PCI: Cannot allocate resource region %d"
                       " of device %s\n", idx, pci_name(dev));
                if (pr)
-                       DBG("PCI:  parent is %p: %08lx-%08lx (f=%lx)\n",
+                       DBG("PCI:  parent is %p: %016llx-%016llx (f=%lx)\n",
                            pr, pr->start, pr->end, pr->flags);
                /* We'll assign a new address later */
                r->flags |= IORESOURCE_UNSET;
@@ -956,7 +957,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
                        res = &hose->io_resource;
                        res->flags = IORESOURCE_IO;
                        res->start = ranges[2];
-                       DBG("PCI: IO 0x%lx -> 0x%lx\n",
+                       DBG("PCI: IO 0x%llx -> 0x%llx\n",
                                    res->start, res->start + size - 1);
                        break;
                case 2:         /* memory space */
@@ -978,7 +979,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
                                if(ranges[0] & 0x40000000)
                                        res->flags |= IORESOURCE_PREFETCH;
                                res->start = ranges[na+2];
-                               DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno,
+                               DBG("PCI: MEM[%d] 0x%llx -> 0x%llx\n", memno,
                                            res->start, res->start + size - 1);
                        }
                        break;
@@ -1074,7 +1075,7 @@ do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
        DBG("Remapping Bus %d, bridge: %s\n", bus->number, pci_name(bridge));
        res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);
        res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
-       DBG("  IO window: %08lx-%08lx\n", res.start, res.end);
+       DBG("  IO window: %016llx-%016llx\n", res.start, res.end);
 
        /* Set up the top and bottom of the PCI I/O segment for this bus. */
        pci_read_config_dword(bridge, PCI_IO_BASE, &l);
@@ -1223,8 +1224,8 @@ do_fixup_p2p_level(struct pci_bus *bus)
                                        continue;
                                if ((r->flags & IORESOURCE_IO) == 0)
                                        continue;
-                               DBG("Trying to allocate from %08lx, size %08lx from parent"
-                                   " res %d: %08lx -> %08lx\n",
+                               DBG("Trying to allocate from %016llx, size %016llx from parent"
+                                   " res %d: %016llx -> %016llx\n",
                                        res->start, res->end, i, r->start, r->end);
                        
                                if (allocate_resource(r, res, res->end + 1, res->start, max,
@@ -1574,8 +1575,8 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
        else
                prot |= _PAGE_GUARDED;
 
-       printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
-              prot);
+       printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev),
+               (unsigned long long)rp->start, prot);
 
        return __pgprot(prot);
 }
@@ -1755,7 +1756,7 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
 
 void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
-                         u64 *start, u64 *end)
+                         resource_size_t *start, resource_size_t *end)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
        unsigned long offset = 0;
index 247937dd8b736aab99a79df9bd6d5711bf951a4a..286aa52aae334db643c5769d5816ee7b6a8ba3f9 100644 (file)
@@ -138,11 +138,11 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       unsigned long start = res->start;
+       resource_size_t start = res->start;
        unsigned long alignto;
 
        if (res->flags & IORESOURCE_IO) {
index 483455c5bb02e5ab00ae04ce6a138168e7f8075b..320c913435cd149a40cd2f8e4f16385184d7bde0 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/kexec.h>
+#include <linux/debugfs.h>
 
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -952,6 +953,7 @@ static struct ibm_pa_feature {
        /* put this back once we know how to test if firmware does 64k IO */
        {CPU_FTR_CI_LARGE_PAGE, 0,      1, 2, 0},
 #endif
+       {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0},
 };
 
 static void __init check_cpu_pa_features(unsigned long node)
@@ -1124,24 +1126,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
                tce_alloc_end = *lprop;
 #endif
 
-#ifdef CONFIG_PPC_RTAS
-       /* To help early debugging via the front panel, we retrieve a minimal
-        * set of RTAS infos now if available
-        */
-       {
-               u64 *basep, *entryp, *sizep;
-
-               basep = of_get_flat_dt_prop(node, "linux,rtas-base", NULL);
-               entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL);
-               sizep = of_get_flat_dt_prop(node, "linux,rtas-size", NULL);
-               if (basep && entryp && sizep) {
-                       rtas.base = *basep;
-                       rtas.entry = *entryp;
-                       rtas.size = *sizep;
-               }
-       }
-#endif /* CONFIG_PPC_RTAS */
-
 #ifdef CONFIG_KEXEC
        lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL);
        if (lprop)
@@ -1326,6 +1310,11 @@ void __init early_init_devtree(void *params)
        /* Setup flat device-tree pointer */
        initial_boot_params = params;
 
+#ifdef CONFIG_PPC_RTAS
+       /* Some machines might need RTAS info for debugging, grab it now. */
+       of_scan_flat_dt(early_init_dt_scan_rtas, NULL);
+#endif
+
        /* Retrieve various informations from the /chosen node of the
         * device-tree, including the platform type, initrd location and
         * size, TCE reserve, and more ...
@@ -2148,3 +2137,27 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
        }
        return NULL;
 }
+
+#ifdef DEBUG
+static struct debugfs_blob_wrapper flat_dt_blob;
+
+static int __init export_flat_device_tree(void)
+{
+       struct dentry *d;
+
+       d = debugfs_create_dir("powerpc", NULL);
+       if (!d)
+               return 1;
+
+       flat_dt_blob.data = initial_boot_params;
+       flat_dt_blob.size = initial_boot_params->totalsize;
+
+       d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
+                               d, &flat_dt_blob);
+       if (!d)
+               return 1;
+
+       return 0;
+}
+__initcall(export_flat_device_tree);
+#endif
index 17dc79198515d8f61f0879b10e9535dbbe5be9ab..4a4cb5598402731afaa5717b25607a5272bab6ec 100644 (file)
 struct rtas_t rtas = {
        .lock = SPIN_LOCK_UNLOCKED
 };
+EXPORT_SYMBOL(rtas);
 
 struct rtas_suspend_me_data {
        long waiting;
        struct rtas_args *args;
 };
 
-EXPORT_SYMBOL(rtas);
-
 DEFINE_SPINLOCK(rtas_data_buf_lock);
+EXPORT_SYMBOL(rtas_data_buf_lock);
+
 char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
+EXPORT_SYMBOL(rtas_data_buf);
+
 unsigned long rtas_rmo_buf;
 
 /*
@@ -106,11 +109,71 @@ static void call_rtas_display_status_delay(char c)
        }
 }
 
-void __init udbg_init_rtas(void)
+void __init udbg_init_rtas_panel(void)
 {
        udbg_putc = call_rtas_display_status_delay;
 }
 
+#ifdef CONFIG_UDBG_RTAS_CONSOLE
+
+/* If you think you're dying before early_init_dt_scan_rtas() does its
+ * work, you can hard code the token values for your firmware here and
+ * hardcode rtas.base/entry etc.
+ */
+static unsigned int rtas_putchar_token = RTAS_UNKNOWN_SERVICE;
+static unsigned int rtas_getchar_token = RTAS_UNKNOWN_SERVICE;
+
+static void udbg_rtascon_putc(char c)
+{
+       int tries;
+
+       if (!rtas.base)
+               return;
+
+       /* Add CRs before LFs */
+       if (c == '\n')
+               udbg_rtascon_putc('\r');
+
+       /* if there is more than one character to be displayed, wait a bit */
+       for (tries = 0; tries < 16; tries++) {
+               if (rtas_call(rtas_putchar_token, 1, 1, NULL, c) == 0)
+                       break;
+               udelay(1000);
+       }
+}
+
+static int udbg_rtascon_getc_poll(void)
+{
+       int c;
+
+       if (!rtas.base)
+               return -1;
+
+       if (rtas_call(rtas_getchar_token, 0, 2, &c))
+               return -1;
+
+       return c;
+}
+
+static int udbg_rtascon_getc(void)
+{
+       int c;
+
+       while ((c = udbg_rtascon_getc_poll()) == -1)
+               ;
+
+       return c;
+}
+
+
+void __init udbg_init_rtas_console(void)
+{
+       udbg_putc = udbg_rtascon_putc;
+       udbg_getc = udbg_rtascon_getc;
+       udbg_getc_poll = udbg_rtascon_getc_poll;
+}
+#endif /* CONFIG_UDBG_RTAS_CONSOLE */
+
 void rtas_progress(char *s, unsigned short hex)
 {
        struct device_node *root;
@@ -236,6 +299,7 @@ int rtas_token(const char *service)
        tokp = (int *) get_property(rtas.dev, service, NULL);
        return tokp ? *tokp : RTAS_UNKNOWN_SERVICE;
 }
+EXPORT_SYMBOL(rtas_token);
 
 #ifdef CONFIG_RTAS_ERROR_LOGGING
 /*
@@ -328,7 +392,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
        char *buff_copy = NULL;
        int ret;
 
-       if (token == RTAS_UNKNOWN_SERVICE)
+       if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
                return -1;
 
        /* Gotta do something different here, use global lock for now... */
@@ -369,6 +433,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
        }
        return ret;
 }
+EXPORT_SYMBOL(rtas_call);
 
 /* For RTAS_BUSY (-2), delay for 1 millisecond.  For an extended busy status
  * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds.
@@ -388,6 +453,7 @@ unsigned int rtas_busy_delay_time(int status)
 
        return ms;
 }
+EXPORT_SYMBOL(rtas_busy_delay_time);
 
 /* For an RTAS busy status code, perform the hinted delay. */
 unsigned int rtas_busy_delay(int status)
@@ -401,6 +467,7 @@ unsigned int rtas_busy_delay(int status)
 
        return ms;
 }
+EXPORT_SYMBOL(rtas_busy_delay);
 
 int rtas_error_rc(int rtas_rc)
 {
@@ -446,6 +513,7 @@ int rtas_get_power_level(int powerdomain, int *level)
                return rtas_error_rc(rc);
        return rc;
 }
+EXPORT_SYMBOL(rtas_get_power_level);
 
 int rtas_set_power_level(int powerdomain, int level, int *setlevel)
 {
@@ -463,6 +531,7 @@ int rtas_set_power_level(int powerdomain, int level, int *setlevel)
                return rtas_error_rc(rc);
        return rc;
 }
+EXPORT_SYMBOL(rtas_set_power_level);
 
 int rtas_get_sensor(int sensor, int index, int *state)
 {
@@ -480,6 +549,7 @@ int rtas_get_sensor(int sensor, int index, int *state)
                return rtas_error_rc(rc);
        return rc;
 }
+EXPORT_SYMBOL(rtas_get_sensor);
 
 int rtas_set_indicator(int indicator, int index, int new_value)
 {
@@ -497,6 +567,7 @@ int rtas_set_indicator(int indicator, int index, int new_value)
                return rtas_error_rc(rc);
        return rc;
 }
+EXPORT_SYMBOL(rtas_set_indicator);
 
 void rtas_restart(char *cmd)
 {
@@ -791,14 +862,34 @@ void __init rtas_initialize(void)
 #endif
 }
 
+int __init early_init_dt_scan_rtas(unsigned long node,
+               const char *uname, int depth, void *data)
+{
+       u32 *basep, *entryp, *sizep;
 
-EXPORT_SYMBOL(rtas_token);
-EXPORT_SYMBOL(rtas_call);
-EXPORT_SYMBOL(rtas_data_buf);
-EXPORT_SYMBOL(rtas_data_buf_lock);
-EXPORT_SYMBOL(rtas_busy_delay_time);
-EXPORT_SYMBOL(rtas_busy_delay);
-EXPORT_SYMBOL(rtas_get_sensor);
-EXPORT_SYMBOL(rtas_get_power_level);
-EXPORT_SYMBOL(rtas_set_power_level);
-EXPORT_SYMBOL(rtas_set_indicator);
+       if (depth != 1 || strcmp(uname, "rtas") != 0)
+               return 0;
+
+       basep  = of_get_flat_dt_prop(node, "linux,rtas-base", NULL);
+       entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL);
+       sizep  = of_get_flat_dt_prop(node, "rtas-size", NULL);
+
+       if (basep && entryp && sizep) {
+               rtas.base = *basep;
+               rtas.entry = *entryp;
+               rtas.size = *sizep;
+       }
+
+#ifdef CONFIG_UDBG_RTAS_CONSOLE
+       basep = of_get_flat_dt_prop(node, "put-term-char", NULL);
+       if (basep)
+               rtas_putchar_token = *basep;
+
+       basep = of_get_flat_dt_prop(node, "get-term-char", NULL);
+       if (basep)
+               rtas_getchar_token = *basep;
+#endif
+
+       /* break now */
+       return 1;
+}
index e5a44812441ac121b980e3d296f19e09651df045..0932a62a1c9637d6834c4872f7f5bca7e2b5d11d 100644 (file)
@@ -215,7 +215,7 @@ int __init ppc_init(void)
 
        /* register CPU devices */
        for_each_possible_cpu(i)
-               register_cpu(&cpu_devices[i], i, NULL);
+               register_cpu(&cpu_devices[i], i);
 
        /* call platform init */
        if (ppc_md.init != NULL) {
index 78f3a5fd43f635b37a1186d056d11c78fb0897c2..175539c9afa066c9b3d2b3596423b0cda5e63a0c 100644 (file)
@@ -149,6 +149,13 @@ early_param("smt-enabled", early_smt_enabled);
 #define check_smt_enabled()
 #endif /* CONFIG_SMP */
 
+/* Put the paca pointer into r13 and SPRG3 */
+void __init setup_paca(int cpu)
+{
+       local_paca = &paca[cpu];
+       mtspr(SPRN_SPRG3, local_paca);
+}
+
 /*
  * Early initialization entry point. This is called by head.S
  * with MMU translation disabled. We rely on the "feature" of
@@ -170,6 +177,9 @@ early_param("smt-enabled", early_smt_enabled);
 
 void __init early_setup(unsigned long dt_ptr)
 {
+       /* Assume we're on cpu 0 for now. Don't write to the paca yet! */
+       setup_paca(0);
+
        /* Enable early debugging if any specified (see udbg.h) */
        udbg_early_init();
 
@@ -183,7 +193,7 @@ void __init early_setup(unsigned long dt_ptr)
        early_init_devtree(__va(dt_ptr));
 
        /* Now we know the logical id of our boot cpu, setup the paca. */
-       setup_boot_paca();
+       setup_paca(boot_cpuid);
 
        /* Fix up paca fields required for the boot cpu */
        get_paca()->cpu_start = 1;
@@ -350,19 +360,11 @@ void __init setup_system(void)
         */
        unflatten_device_tree();
 
-#ifdef CONFIG_KEXEC
-       kexec_setup();  /* requires unflattened device tree. */
-#endif
-
        /*
         * Fill the ppc64_caches & systemcfg structures with informations
         * retrieved from the device-tree. Need to be called before
         * finish_device_tree() since the later requires some of the
-        * informations filled up here to properly parse the interrupt
-        * tree.
-        * It also sets up the cache line sizes which allows to call
-        * routines like flush_icache_range (used by the hash init
-        * later on).
+        * informations filled up here to properly parse the interrupt tree.
         */
        initialize_cache_info();
 
index 5bc2585c8036d97e08b8fff0c174cce01ad61c14..4662b580efa1648939eb9e03ec932dd6b63680e2 100644 (file)
@@ -279,7 +279,7 @@ static void unregister_cpu_online(unsigned int cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static int sysfs_cpu_notify(struct notifier_block *self,
+static int __devinit sysfs_cpu_notify(struct notifier_block *self,
                                      unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned int)(long)hcpu;
@@ -297,30 +297,19 @@ static int sysfs_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block sysfs_cpu_nb = {
+static struct notifier_block __devinitdata sysfs_cpu_nb = {
        .notifier_call  = sysfs_cpu_notify,
 };
 
 /* NUMA stuff */
 
 #ifdef CONFIG_NUMA
-static struct node node_devices[MAX_NUMNODES];
-
 static void register_nodes(void)
 {
        int i;
 
-       for (i = 0; i < MAX_NUMNODES; i++) {
-               if (node_online(i)) {
-                       int p_node = parent_node(i);
-                       struct node *parent = NULL;
-
-                       if (p_node != i)
-                               parent = &node_devices[p_node];
-
-                       register_node(&node_devices[i], i, parent);
-               }
-       }
+       for (i = 0; i < MAX_NUMNODES; i++)
+               register_one_node(i);
 }
 
 int sysfs_add_device_to_node(struct sys_device *dev, int nid)
@@ -359,23 +348,13 @@ static SYSDEV_ATTR(physical_id, 0444, show_physical_id, NULL);
 static int __init topology_init(void)
 {
        int cpu;
-       struct node *parent = NULL;
 
        register_nodes();
-
        register_cpu_notifier(&sysfs_cpu_nb);
 
        for_each_possible_cpu(cpu) {
                struct cpu *c = &per_cpu(cpu_devices, cpu);
 
-#ifdef CONFIG_NUMA
-               /* The node to which a cpu belongs can't be known
-                * until the cpu is made present.
-                */
-               parent = NULL;
-               if (cpu_present(cpu))
-                       parent = &node_devices[cpu_to_node(cpu)];
-#endif
                /*
                 * For now, we just see if the system supports making
                 * the RTAS calls for CPU hotplug.  But, there may be a
@@ -387,7 +366,7 @@ static int __init topology_init(void)
                        c->no_control = 1;
 
                if (cpu_online(cpu) || (c->no_control == 0)) {
-                       register_cpu(c, cpu, parent);
+                       register_cpu(c, cpu);
 
                        sysdev_create_file(&c->sysdev, &attr_physical_id);
                }
index 52f5659534f48042da4f68ddaad02806f70a3a0c..fa6bd97b6b9d59c30fd4897dd241c53064d28339 100644 (file)
 #include <asm/firmware.h>
 #include <asm/processor.h>
 #endif
+#include <asm/kexec.h>
 
 #ifdef CONFIG_PPC64    /* XXX */
 #define _IO_BASE       pci_io_base
+#ifdef CONFIG_KEXEC
+cpumask_t cpus_in_sr = CPU_MASK_NONE;
+#endif
 #endif
 
 #ifdef CONFIG_DEBUGGER
@@ -97,7 +101,7 @@ static DEFINE_SPINLOCK(die_lock);
 
 int die(const char *str, struct pt_regs *regs, long err)
 {
-       static int die_counter, crash_dump_start = 0;
+       static int die_counter;
 
        if (debugger(regs))
                return 1;
@@ -137,21 +141,12 @@ int die(const char *str, struct pt_regs *regs, long err)
        print_modules();
        show_regs(regs);
        bust_spinlocks(0);
+       spin_unlock_irq(&die_lock);
 
-       if (!crash_dump_start && kexec_should_crash(current)) {
-               crash_dump_start = 1;
-               spin_unlock_irq(&die_lock);
+       if (kexec_should_crash(current) ||
+               kexec_sr_activated(smp_processor_id()))
                crash_kexec(regs);
-               /* NOTREACHED */
-       }
-       spin_unlock_irq(&die_lock);
-       if (crash_dump_start)
-               /*
-                * Only for soft-reset: Other CPUs will be responded to an IPI
-                * sent by first kexec CPU.
-                */
-               for(;;)
-                       ;
+       crash_kexec_secondary(regs);
 
        if (in_interrupt())
                panic("Fatal exception in interrupt");
@@ -215,6 +210,10 @@ void system_reset_exception(struct pt_regs *regs)
                        return;
        }
 
+#ifdef CONFIG_KEXEC
+       cpu_set(smp_processor_id(), cpus_in_sr);
+#endif
+
        die("System Reset", regs, SIGABRT);
 
        /* Must die if the interrupt is not recoverable */
index 67d9fd9ae2b53092cc2bf7727f29060f4331f921..759afd5e0d8a3c8a567c7609facb75264930a4aa 100644 (file)
@@ -34,9 +34,12 @@ void __init udbg_early_init(void)
 #elif defined(CONFIG_PPC_EARLY_DEBUG_G5)
        /* For use on Apple G5 machines */
        udbg_init_pmac_realmode();
-#elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS)
+#elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL)
        /* RTAS panel debug */
-       udbg_init_rtas();
+       udbg_init_rtas_panel();
+#elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE)
+       /* RTAS console debug */
+       udbg_init_rtas_console();
 #elif defined(CONFIG_PPC_EARLY_DEBUG_MAPLE)
        /* Maple real mode debug */
        udbg_init_maple_realmode();
index a0f3cbd00d397a3356cf2162340580dcdfe6d78d..c90f124f3c71caed159f9eb04b6ab5b85d6194ed 100644 (file)
@@ -520,7 +520,7 @@ static inline int tlb_batching_enabled(void)
 }
 #endif
 
-void hpte_init_native(void)
+void __init hpte_init_native(void)
 {
        ppc_md.hpte_invalidate  = native_hpte_invalidate;
        ppc_md.hpte_updatepp    = native_hpte_updatepp;
@@ -530,5 +530,4 @@ void hpte_init_native(void)
        ppc_md.hpte_clear_all   = native_hpte_clear;
        if (tlb_batching_enabled())
                ppc_md.flush_hash_range = native_flush_hash_range;
-       htab_finish_init();
 }
index d03fd2b4445e1f43e5cde417b760e71f227d9f84..3cc6d68f71171f3d8953d753a7bd671c3b8fb474 100644 (file)
@@ -167,34 +167,12 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
                hash = hpt_hash(va, shift);
                hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
 
-               /* The crap below can be cleaned once ppd_md.probe() can
-                * set up the hash callbacks, thus we can just used the
-                * normal insert callback here.
-                */
-#ifdef CONFIG_PPC_ISERIES
-               if (machine_is(iseries))
-                       ret = iSeries_hpte_insert(hpteg, va,
-                                                 paddr,
-                                                 tmp_mode,
-                                                 HPTE_V_BOLTED,
-                                                 psize);
-               else
-#endif
-#ifdef CONFIG_PPC_PSERIES
-               if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR))
-                       ret = pSeries_lpar_hpte_insert(hpteg, va,
-                                                      paddr,
-                                                      tmp_mode,
-                                                      HPTE_V_BOLTED,
-                                                      psize);
-               else
-#endif
-#ifdef CONFIG_PPC_MULTIPLATFORM
-                       ret = native_hpte_insert(hpteg, va,
-                                                paddr,
-                                                tmp_mode, HPTE_V_BOLTED,
-                                                psize);
-#endif
+               DBG("htab_bolt_mapping: calling %p\n", ppc_md.hpte_insert);
+
+               BUG_ON(!ppc_md.hpte_insert);
+               ret = ppc_md.hpte_insert(hpteg, va, paddr,
+                               tmp_mode, HPTE_V_BOLTED, psize);
+
                if (ret < 0)
                        break;
        }
@@ -413,6 +391,41 @@ void create_section_mapping(unsigned long start, unsigned long end)
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
+static inline void make_bl(unsigned int *insn_addr, void *func)
+{
+       unsigned long funcp = *((unsigned long *)func);
+       int offset = funcp - (unsigned long)insn_addr;
+
+       *insn_addr = (unsigned int)(0x48000001 | (offset & 0x03fffffc));
+       flush_icache_range((unsigned long)insn_addr, 4+
+                          (unsigned long)insn_addr);
+}
+
+static void __init htab_finish_init(void)
+{
+       extern unsigned int *htab_call_hpte_insert1;
+       extern unsigned int *htab_call_hpte_insert2;
+       extern unsigned int *htab_call_hpte_remove;
+       extern unsigned int *htab_call_hpte_updatepp;
+
+#ifdef CONFIG_PPC_64K_PAGES
+       extern unsigned int *ht64_call_hpte_insert1;
+       extern unsigned int *ht64_call_hpte_insert2;
+       extern unsigned int *ht64_call_hpte_remove;
+       extern unsigned int *ht64_call_hpte_updatepp;
+
+       make_bl(ht64_call_hpte_insert1, ppc_md.hpte_insert);
+       make_bl(ht64_call_hpte_insert2, ppc_md.hpte_insert);
+       make_bl(ht64_call_hpte_remove, ppc_md.hpte_remove);
+       make_bl(ht64_call_hpte_updatepp, ppc_md.hpte_updatepp);
+#endif /* CONFIG_PPC_64K_PAGES */
+
+       make_bl(htab_call_hpte_insert1, ppc_md.hpte_insert);
+       make_bl(htab_call_hpte_insert2, ppc_md.hpte_insert);
+       make_bl(htab_call_hpte_remove, ppc_md.hpte_remove);
+       make_bl(htab_call_hpte_updatepp, ppc_md.hpte_updatepp);
+}
+
 void __init htab_initialize(void)
 {
        unsigned long table;
@@ -525,6 +538,8 @@ void __init htab_initialize(void)
                                         mmu_linear_psize));
        }
 
+       htab_finish_init();
+
        DBG(" <- htab_initialize()\n");
 }
 #undef KB
@@ -787,16 +802,6 @@ void flush_hash_range(unsigned long number, int local)
        }
 }
 
-static inline void make_bl(unsigned int *insn_addr, void *func)
-{
-       unsigned long funcp = *((unsigned long *)func);
-       int offset = funcp - (unsigned long)insn_addr;
-
-       *insn_addr = (unsigned int)(0x48000001 | (offset & 0x03fffffc));
-       flush_icache_range((unsigned long)insn_addr, 4+
-                          (unsigned long)insn_addr);
-}
-
 /*
  * low_hash_fault is called when we the low level hash code failed
  * to instert a PTE due to an hypervisor error
@@ -815,28 +820,3 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address)
        }
        bad_page_fault(regs, address, SIGBUS);
 }
-
-void __init htab_finish_init(void)
-{
-       extern unsigned int *htab_call_hpte_insert1;
-       extern unsigned int *htab_call_hpte_insert2;
-       extern unsigned int *htab_call_hpte_remove;
-       extern unsigned int *htab_call_hpte_updatepp;
-
-#ifdef CONFIG_PPC_64K_PAGES
-       extern unsigned int *ht64_call_hpte_insert1;
-       extern unsigned int *ht64_call_hpte_insert2;
-       extern unsigned int *ht64_call_hpte_remove;
-       extern unsigned int *ht64_call_hpte_updatepp;
-
-       make_bl(ht64_call_hpte_insert1, ppc_md.hpte_insert);
-       make_bl(ht64_call_hpte_insert2, ppc_md.hpte_insert);
-       make_bl(ht64_call_hpte_remove, ppc_md.hpte_remove);
-       make_bl(ht64_call_hpte_updatepp, ppc_md.hpte_updatepp);
-#endif /* CONFIG_PPC_64K_PAGES */
-
-       make_bl(htab_call_hpte_insert1, ppc_md.hpte_insert);
-       make_bl(htab_call_hpte_insert2, ppc_md.hpte_insert);
-       make_bl(htab_call_hpte_remove, ppc_md.hpte_remove);
-       make_bl(htab_call_hpte_updatepp, ppc_md.hpte_updatepp);
-}
index 9e30f968c184af90dfad58f5ff357edfe81e0ed3..d454caada265d599addca7877ced6e5f7a318e04 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/idr.h>
 #include <linux/nodemask.h>
 #include <linux/module.h>
+#include <linux/poison.h>
 
 #include <asm/pgalloc.h>
 #include <asm/page.h>
@@ -90,7 +91,7 @@ void free_initmem(void)
 
        addr = (unsigned long)__init_begin;
        for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
-               memset((void *)addr, 0xcc, PAGE_SIZE);
+               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
                ClearPageReserved(virt_to_page(addr));
                init_page_count(virt_to_page(addr));
                free_page(addr);
index 69f3b9a20beb768a093735b800628e18f3d1645f..089d939a0b3e9829b037cc95d38e27e2180746f9 100644 (file)
@@ -114,15 +114,20 @@ void online_page(struct page *page)
        num_physpages++;
 }
 
-int __devinit add_memory(u64 start, u64 size)
+#ifdef CONFIG_NUMA
+int memory_add_physaddr_to_nid(u64 start)
+{
+       return hot_add_scn_to_nid(start);
+}
+#endif
+
+int __devinit arch_add_memory(int nid, u64 start, u64 size)
 {
        struct pglist_data *pgdata;
        struct zone *zone;
-       int nid;
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
 
-       nid = hot_add_scn_to_nid(start);
        pgdata = NODE_DATA(nid);
 
        start = (unsigned long)__va(start);
index 65d18dca266ff0e3b26ed1212ca3da5990ee150c..e2051efa09c58d413d95814615c94f2d683b8b22 100644 (file)
@@ -44,7 +44,9 @@ again:
                return err;
 
        if (index > MAX_CONTEXT) {
+               spin_lock(&mmu_context_lock);
                idr_remove(&mmu_context_idr, index);
+               spin_unlock(&mmu_context_lock);
                return -ENOMEM;
        }
 
index aa98cb3b59d82a3c9ff49f35089ba0244eca60d6..fbe23933f73192662b1780ff7d99c728a4eddaf9 100644 (file)
@@ -334,7 +334,7 @@ out:
        return nid;
 }
 
-static int cpu_numa_callback(struct notifier_block *nfb,
+static int __cpuinit cpu_numa_callback(struct notifier_block *nfb,
                             unsigned long action,
                             void *hcpu)
 {
@@ -609,14 +609,15 @@ static void __init *careful_allocation(int nid, unsigned long size,
        return (void *)ret;
 }
 
+static struct notifier_block __cpuinitdata ppc64_numa_nb = {
+       .notifier_call = cpu_numa_callback,
+       .priority = 1 /* Must run before sched domains notifier. */
+};
+
 void __init do_init_bootmem(void)
 {
        int nid;
        unsigned int i;
-       static struct notifier_block ppc64_numa_nb = {
-               .notifier_call = cpu_numa_callback,
-               .priority = 1 /* Must run before sched domains notifier. */
-       };
 
        min_low_pfn = 0;
        max_low_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT;
index 16f7d3b30e1dbf023e0229fe946441516fc3c845..3baceb00fefaacde0f2929e8572e17c8b3282960 100644 (file)
@@ -91,9 +91,10 @@ int __init add_bridge(struct device_node *dev)
                mpc83xx_pci2_busno = hose->first_busno;
        }
 
-       printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%08lx. "
+       printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. "
               "Firmware bus number: %d->%d\n",
-              rsrc.start, hose->first_busno, hose->last_busno);
+              (unsigned long long)rsrc.start, hose->first_busno,
+              hose->last_busno);
 
        DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
            hose, hose->cfg_addr, hose->cfg_data);
index bad290110ed1dcc34373b80670cefe770aee2587..48c8849c07ca39614caf78ae02206fa1a23dfdc1 100644 (file)
@@ -79,9 +79,10 @@ int __init add_bridge(struct device_node *dev)
                mpc85xx_pci2_busno = hose->first_busno;
        }
 
-       printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%08lx. "
+       printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%016llx. "
               "Firmware bus number: %d->%d\n",
-               rsrc.start, hose->first_busno, hose->last_busno);
+               (unsigned long long)rsrc.start, hose->first_busno,
+               hose->last_busno);
 
        DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
                hose, hose->cfg_addr, hose->cfg_data);
index 3a87863d287611d94984dc06c35a2ade3d6c5449..d1ecc0f9ab586164277dd12c27021af74d00a836 100644 (file)
@@ -7,6 +7,7 @@ choice
 
 config MPC8641_HPCN
        bool "Freescale MPC8641 HPCN"
+       select PPC_I8259
        help
          This option enables support for the MPC8641 HPCN board.
 
@@ -28,9 +29,4 @@ config PPC_INDIRECT_PCI_BE
        depends on PPC_86xx
        default y
 
-config PPC_STD_MMU
-       bool
-       depends on PPC_86xx
-       default y
-
 endmenu
index 7be796c5d5c942c7a0d1dff0c3c9666ccc0a1211..476a6eeee710d314eb2ad4eba2a2987b71d5d9aa 100644 (file)
@@ -2,9 +2,6 @@
 # Makefile for the PowerPC 86xx linux kernel.
 #
 
-
-ifeq ($(CONFIG_PPC_86xx),y)
 obj-$(CONFIG_SMP)              += mpc86xx_smp.o
-endif
 obj-$(CONFIG_MPC8641_HPCN)     += mpc86xx_hpcn.o
 obj-$(CONFIG_PCI)              += pci.o mpc86xx_pcie.o
index 5042253758b7b30a295cfcef994c1d206f3eccd2..5d2bcf78cef70e2ac323877e7af79c76d0ed9496 100644 (file)
@@ -14,7 +14,6 @@
 #ifndef __MPC8641_HPCN_H__
 #define __MPC8641_HPCN_H__
 
-#include <linux/config.h>
 #include <linux/init.h>
 
 /* PCI interrupt controller */
index e3c9e4f417d39f95505e118c7a7b5dfedef743a6..2834462590b809ae80de941d77a46aa925bc24e1 100644 (file)
  * mpc86xx_* files. Mostly for use by mpc86xx_setup().
  */
 
-extern int __init add_bridge(struct device_node *dev);
+extern int add_bridge(struct device_node *dev);
 
-extern void __init setup_indirect_pcie(struct pci_controller *hose,
+extern int mpc86xx_exclude_device(u_char bus, u_char devfn);
+
+extern void setup_indirect_pcie(struct pci_controller *hose,
                                       u32 cfg_addr, u32 cfg_data);
-extern void __init setup_indirect_pcie_nomap(struct pci_controller *hose,
+extern void setup_indirect_pcie_nomap(struct pci_controller *hose,
                                             void __iomem *cfg_addr,
                                             void __iomem *cfg_data);
 
index 483c21df181ec1e9938de9295fa3a199a4a6eb34..ebae73eb00630f460a926e9b56dfbf004cd1756d 100644 (file)
@@ -12,7 +12,6 @@
  * option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -36,6 +35,7 @@
 #include <sysdev/fsl_soc.h>
 
 #include "mpc86xx.h"
+#include "mpc8641_hpcn.h"
 
 #ifndef CONFIG_PCI
 unsigned long isa_io_base = 0;
@@ -186,17 +186,130 @@ mpc86xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
        return PCI_IRQ_TABLE_LOOKUP + I8259_OFFSET;
 }
 
+static void __devinit quirk_ali1575(struct pci_dev *dev)
+{
+       unsigned short temp;
+
+       /*
+        * ALI1575 interrupts route table setup:
+        *
+        * IRQ pin   IRQ#
+        * PIRQA ---- 3
+        * PIRQB ---- 4
+        * PIRQC ---- 5
+        * PIRQD ---- 6
+        * PIRQE ---- 9
+        * PIRQF ---- 10
+        * PIRQG ---- 11
+        * PIRQH ---- 12
+        *
+        * interrupts for PCI slot0 -- PIRQA / PIRQB / PIRQC / PIRQD
+        *                PCI slot1 -- PIRQB / PIRQC / PIRQD / PIRQA
+        */
+       pci_write_config_dword(dev, 0x48, 0xb9317542);
+
+       /* USB 1.1 OHCI controller 1, interrupt: PIRQE */
+       pci_write_config_byte(dev, 0x86, 0x0c);
+
+       /* USB 1.1 OHCI controller 2, interrupt: PIRQF */
+       pci_write_config_byte(dev, 0x87, 0x0d);
+
+       /* USB 1.1 OHCI controller 3, interrupt: PIRQH */
+       pci_write_config_byte(dev, 0x88, 0x0f);
+
+       /* USB 2.0 controller, interrupt: PIRQ7 */
+       pci_write_config_byte(dev, 0x74, 0x06);
+
+       /* Audio controller, interrupt: PIRQE */
+       pci_write_config_byte(dev, 0x8a, 0x0c);
+
+       /* Modem controller, interrupt: PIRQF */
+       pci_write_config_byte(dev, 0x8b, 0x0d);
+
+       /* HD audio controller, interrupt: PIRQG */
+       pci_write_config_byte(dev, 0x8c, 0x0e);
+
+       /* Serial ATA interrupt: PIRQD */
+       pci_write_config_byte(dev, 0x8d, 0x0b);
+
+       /* SMB interrupt: PIRQH */
+       pci_write_config_byte(dev, 0x8e, 0x0f);
+
+       /* PMU ACPI SCI interrupt: PIRQH */
+       pci_write_config_byte(dev, 0x8f, 0x0f);
+
+       /* Primary PATA IDE IRQ: 14
+        * Secondary PATA IDE IRQ: 15
+        */
+       pci_write_config_byte(dev, 0x44, 0x3d);
+       pci_write_config_byte(dev, 0x75, 0x0f);
+
+       /* Set IRQ14 and IRQ15 to legacy IRQs */
+       pci_read_config_word(dev, 0x46, &temp);
+       temp |= 0xc000;
+       pci_write_config_word(dev, 0x46, temp);
+
+       /* Set i8259 interrupt trigger
+        * IRQ 3:  Level
+        * IRQ 4:  Level
+        * IRQ 5:  Level
+        * IRQ 6:  Level
+        * IRQ 7:  Level
+        * IRQ 9:  Level
+        * IRQ 10: Level
+        * IRQ 11: Level
+        * IRQ 12: Level
+        * IRQ 14: Edge
+        * IRQ 15: Edge
+        */
+       outb(0xfa, 0x4d0);
+       outb(0x1e, 0x4d1);
+}
 
-int
-mpc86xx_exclude_device(u_char bus, u_char devfn)
+static void __devinit quirk_uli5288(struct pci_dev *dev)
 {
-#if !defined(CONFIG_PCI)
-       if (bus == 0 && PCI_SLOT(devfn) == 0)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-#endif
+       unsigned char c;
+
+       pci_read_config_byte(dev,0x83,&c);
+       c |= 0x80;
+       pci_write_config_byte(dev, 0x83, c);
+
+       pci_write_config_byte(dev, 0x09, 0x01);
+       pci_write_config_byte(dev, 0x0a, 0x06);
+
+       pci_read_config_byte(dev,0x83,&c);
+       c &= 0x7f;
+       pci_write_config_byte(dev, 0x83, c);
 
-       return PCIBIOS_SUCCESSFUL;
+       pci_read_config_byte(dev,0x84,&c);
+       c |= 0x01;
+       pci_write_config_byte(dev, 0x84, c);
 }
+
+static void __devinit quirk_uli5229(struct pci_dev *dev)
+{
+       unsigned short temp;
+       pci_write_config_word(dev, 0x04, 0x0405);
+       pci_read_config_word(dev, 0x4a, &temp);
+       temp |= 0x1000;
+       pci_write_config_word(dev, 0x4a, temp);
+}
+
+static void __devinit early_uli5249(struct pci_dev *dev)
+{
+       unsigned char temp;
+       pci_write_config_word(dev, 0x04, 0x0007);
+       pci_read_config_byte(dev, 0x7c, &temp);
+       pci_write_config_byte(dev, 0x7c, 0x80);
+       pci_write_config_byte(dev, 0x09, 0x01);
+       pci_write_config_byte(dev, 0x7c, temp);
+       dev->class |= 0x1;
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, quirk_ali1575);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5288, quirk_uli5288);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, 0x5249, early_uli5249);
 #endif /* CONFIG_PCI */
 
 
index 944ec4b714160c5b9498a4a641e7be20c9ec2950..bb7fb41933ad8abe557ae857ceaaf5b8d3f22d53 100644 (file)
@@ -10,7 +10,6 @@
  * option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -34,8 +33,8 @@ extern unsigned long __secondary_hold_acknowledge;
 static void __init
 smp_86xx_release_core(int nr)
 {
-       void *mcm_vaddr;
-       unsigned long vaddr, pcr;
+       __be32 __iomem *mcm_vaddr;
+       unsigned long pcr;
 
        if (nr < 0 || nr >= NR_CPUS)
                return;
@@ -45,10 +44,9 @@ smp_86xx_release_core(int nr)
         */
        mcm_vaddr = ioremap(get_immrbase() + MPC86xx_MCM_OFFSET,
                            MPC86xx_MCM_SIZE);
-       vaddr = (unsigned long)mcm_vaddr +  MCM_PORT_CONFIG_OFFSET;
-       pcr = in_be32((volatile unsigned *)vaddr);
+       pcr = in_be32(mcm_vaddr + (MCM_PORT_CONFIG_OFFSET >> 2));
        pcr |= 1 << (nr + 24);
-       out_be32((volatile unsigned *)vaddr, pcr);
+       out_be32(mcm_vaddr + (MCM_PORT_CONFIG_OFFSET >> 2), pcr);
 }
 
 
index 5180df7c75bc34b566a6e66f72edb59e477bd711..bc5139043112e934f340b2691dabddadad355abc 100644 (file)
@@ -12,7 +12,6 @@
  * option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -122,15 +121,12 @@ static void __init setup_pcie_atmu(struct pci_controller *hose, struct resource
 static void __init
 mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size)
 {
-       volatile struct ccsr_pex *pcie;
        u16 cmd;
        unsigned int temps;
 
        DBG("PCIE host controller register offset 0x%08x, size 0x%08x.\n",
                        pcie_offset, pcie_size);
 
-       pcie = ioremap(pcie_offset, pcie_size);
-
        early_read_config_word(hose, 0, 0, PCI_COMMAND, &cmd);
        cmd |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
            | PCI_COMMAND_IO;
@@ -144,6 +140,14 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size)
        early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps);
 }
 
+int mpc86xx_exclude_device(u_char bus, u_char devfn)
+{
+       if (bus == 0 && PCI_SLOT(devfn) == 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
 int __init add_bridge(struct device_node *dev)
 {
        int len;
@@ -198,128 +202,3 @@ int __init add_bridge(struct device_node *dev)
 
        return 0;
 }
-
-static void __devinit quirk_ali1575(struct pci_dev *dev)
-{
-       unsigned short temp;
-
-       /*
-        * ALI1575 interrupts route table setup:
-        *
-        * IRQ pin   IRQ#
-        * PIRQA ---- 3
-        * PIRQB ---- 4
-        * PIRQC ---- 5
-        * PIRQD ---- 6
-        * PIRQE ---- 9
-        * PIRQF ---- 10
-        * PIRQG ---- 11
-        * PIRQH ---- 12
-        *
-        * interrupts for PCI slot0 -- PIRQA / PIRQB / PIRQC / PIRQD
-        *                PCI slot1 -- PIRQB / PIRQC / PIRQD / PIRQA
-        */
-       pci_write_config_dword(dev, 0x48, 0xb9317542);
-
-       /* USB 1.1 OHCI controller 1, interrupt: PIRQE */
-       pci_write_config_byte(dev, 0x86, 0x0c);
-
-       /* USB 1.1 OHCI controller 2, interrupt: PIRQF */
-       pci_write_config_byte(dev, 0x87, 0x0d);
-
-       /* USB 1.1 OHCI controller 3, interrupt: PIRQH */
-       pci_write_config_byte(dev, 0x88, 0x0f);
-
-       /* USB 2.0 controller, interrupt: PIRQ7 */
-       pci_write_config_byte(dev, 0x74, 0x06);
-
-       /* Audio controller, interrupt: PIRQE */
-       pci_write_config_byte(dev, 0x8a, 0x0c);
-
-       /* Modem controller, interrupt: PIRQF */
-       pci_write_config_byte(dev, 0x8b, 0x0d);
-
-       /* HD audio controller, interrupt: PIRQG */
-       pci_write_config_byte(dev, 0x8c, 0x0e);
-
-       /* Serial ATA interrupt: PIRQD */
-       pci_write_config_byte(dev, 0x8d, 0x0b);
-
-       /* SMB interrupt: PIRQH */
-       pci_write_config_byte(dev, 0x8e, 0x0f);
-
-       /* PMU ACPI SCI interrupt: PIRQH */
-       pci_write_config_byte(dev, 0x8f, 0x0f);
-
-       /* Primary PATA IDE IRQ: 14
-        * Secondary PATA IDE IRQ: 15
-        */
-       pci_write_config_byte(dev, 0x44, 0x3d);
-       pci_write_config_byte(dev, 0x75, 0x0f);
-
-       /* Set IRQ14 and IRQ15 to legacy IRQs */
-       pci_read_config_word(dev, 0x46, &temp);
-       temp |= 0xc000;
-       pci_write_config_word(dev, 0x46, temp);
-
-       /* Set i8259 interrupt trigger
-        * IRQ 3:  Level
-        * IRQ 4:  Level
-        * IRQ 5:  Level
-        * IRQ 6:  Level
-        * IRQ 7:  Level
-        * IRQ 9:  Level
-        * IRQ 10: Level
-        * IRQ 11: Level
-        * IRQ 12: Level
-        * IRQ 14: Edge
-        * IRQ 15: Edge
-        */
-       outb(0xfa, 0x4d0);
-       outb(0x1e, 0x4d1);
-}
-
-static void __devinit quirk_uli5288(struct pci_dev *dev)
-{
-       unsigned char c;
-
-       pci_read_config_byte(dev,0x83,&c);
-       c |= 0x80;
-       pci_write_config_byte(dev, 0x83, c);
-
-       pci_write_config_byte(dev, 0x09, 0x01);
-       pci_write_config_byte(dev, 0x0a, 0x06);
-
-       pci_read_config_byte(dev,0x83,&c);
-       c &= 0x7f;
-       pci_write_config_byte(dev, 0x83, c);
-
-       pci_read_config_byte(dev,0x84,&c);
-       c |= 0x01;
-       pci_write_config_byte(dev, 0x84, c);
-}
-
-static void __devinit quirk_uli5229(struct pci_dev *dev)
-{
-       unsigned short temp;
-       pci_write_config_word(dev, 0x04, 0x0405);
-       pci_read_config_word(dev, 0x4a, &temp);
-       temp |= 0x1000;
-       pci_write_config_word(dev, 0x4a, temp);
-}
-
-static void __devinit early_uli5249(struct pci_dev *dev)
-{
-       unsigned char temp;
-       pci_write_config_word(dev, 0x04, 0x0007);
-       pci_read_config_byte(dev, 0x7c, &temp);
-       pci_write_config_byte(dev, 0x7c, 0x80);
-       pci_write_config_byte(dev, 0x09, 0x01);
-       pci_write_config_byte(dev, 0x7c, temp);
-       dev->class |= 0x1;
-}
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, quirk_ali1575);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5288, quirk_uli5288);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229);
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, 0x5249, early_uli5249);
index 292863694562b713b1ae194ba85b102ebf994942..5cf46dc57895671e5c17f1170f879f4a2d0f0730 100644 (file)
@@ -14,3 +14,4 @@ obj-$(CONFIG_PPC_PSERIES)     += pseries/
 obj-$(CONFIG_PPC_ISERIES)      += iseries/
 obj-$(CONFIG_PPC_MAPLE)                += maple/
 obj-$(CONFIG_PPC_CELL)         += cell/
+obj-$(CONFIG_EMBEDDED6xx)      += embedded6xx/
index 352bbbacde9ad478fe8a8f02603cd3ed5be26e22..0c8c7b6ab897657866c37212195f87acba59a860 100644 (file)
@@ -6,6 +6,7 @@ config SPU_FS
        default m
        depends on PPC_CELL
        select SPU_BASE
+       select MEMORY_HOTPLUG
        help
          The SPU file system is used to access Synergistic Processing
          Units on machines implementing the Broadband Processor
@@ -18,7 +19,6 @@ config SPU_BASE
 config SPUFS_MMAP
        bool
        depends on SPU_FS && SPARSEMEM
-       select MEMORY_HOTPLUG
        default y
 
 config CBE_RAS
index 1bbf822b4efcafada7f9181af9de762772f37f29..7bff3cbc5723b1615b28a46c1e62fe91cdebaccd 100644 (file)
@@ -307,7 +307,7 @@ static void iic_request_ipi(int ipi, const char *name)
        irq = iic_ipi_to_irq(ipi);
        /* IPIs are marked SA_INTERRUPT as they must run with irqs
         * disabled */
-       get_irq_desc(irq)->handler = &iic_pic;
+       get_irq_desc(irq)->chip = &iic_pic;
        get_irq_desc(irq)->status |= IRQ_PER_CPU;
        request_irq(irq, iic_ipi_action, SA_INTERRUPT, name, NULL);
 }
@@ -330,7 +330,7 @@ static void iic_setup_spe_handlers(void)
        for (be=0; be < num_present_cpus() / 2; be++) {
                for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) {
                        int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
-                       get_irq_desc(irq)->handler = &iic_pic;
+                       get_irq_desc(irq)->chip = &iic_pic;
                }
        }
 }
index 3d1831d331e5de73c8f17ae3b789610d438ed04b..00d112f92272fcda65c20adece8499b68e6bb318 100644 (file)
@@ -125,8 +125,6 @@ static void __init cell_init_early(void)
 {
        DBG(" -> cell_init_early()\n");
 
-       hpte_init_native();
-
        cell_init_iommu();
 
        ppc64_interrupt_controller = IC_CELL_PIC;
@@ -139,11 +137,17 @@ static int __init cell_probe(void)
 {
        unsigned long root = of_get_flat_dt_root();
 
-       if (of_flat_dt_is_compatible(root, "IBM,CBEA") ||
-           of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
-               return 1;
+       if (!of_flat_dt_is_compatible(root, "IBM,CBEA") &&
+           !of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
+               return 0;
+
+#ifdef CONFIG_UDBG_RTAS_CONSOLE
+       udbg_init_rtas_console();
+#endif
+
+       hpte_init_native();
 
-       return 0;
+       return 1;
 }
 
 /*
index 55cbdd77a62dc417136209438e7e249622283ce3..7c3a0b6d34fdffb443ebaab6771575423a50f241 100644 (file)
@@ -162,7 +162,7 @@ void spider_init_IRQ_hardcoded(void)
                spider_pics[node] = ioremap(spiderpic, 0x800);
                for (n = 0; n < IIC_NUM_EXT; n++) {
                        int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
-                       get_irq_desc(irq)->handler = &spider_pic;
+                       get_irq_desc(irq)->chip = &spider_pic;
                }
 
                /* do not mask any interrupts because of level */
@@ -217,7 +217,7 @@ void spider_init_IRQ(void)
 
                for (n = 0; n < IIC_NUM_EXT; n++) {
                        int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
-                       get_irq_desc(irq)->handler = &spider_pic;
+                       get_irq_desc(irq)->chip = &spider_pic;
                }
 
                /* do not mask any interrupts because of level */
index db82f503ba2cc53ad11cfca0ac2193a9ff8d2a99..b306723abb87ba2f07f3169cfed713e54dc9e152 100644 (file)
@@ -168,12 +168,12 @@ spu_irq_class_0_bottom(struct spu *spu)
 
        stat &= mask;
 
-       if (stat & 1) /* invalid MFC DMA */
-               __spu_trap_invalid_dma(spu);
-
-       if (stat & 2) /* invalid DMA alignment */
+       if (stat & 1) /* invalid DMA alignment */
                __spu_trap_dma_align(spu);
 
+       if (stat & 2) /* invalid MFC DMA */
+               __spu_trap_invalid_dma(spu);
+
        if (stat & 4) /* error on SPU */
                __spu_trap_error(spu);
 
index 7854a380dce257c13732f7a067fa8f58941e6bae..58e794f9da1b6a5b920f95ba6fe57f0f054d1cb7 100644 (file)
@@ -204,7 +204,7 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
 
        vma->vm_flags |= VM_RESERVED;
        vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-                                    | _PAGE_NO_CACHE);
+                                    | _PAGE_NO_CACHE | _PAGE_GUARDED);
 
        vma->vm_ops = &spufs_cntl_mmap_vmops;
        return 0;
@@ -675,7 +675,7 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
 
        vma->vm_flags |= VM_RESERVED;
        vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-                                    | _PAGE_NO_CACHE);
+                                    | _PAGE_NO_CACHE | _PAGE_GUARDED);
 
        vma->vm_ops = &spufs_signal1_mmap_vmops;
        return 0;
@@ -762,7 +762,7 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
        /* FIXME: */
        vma->vm_flags |= VM_RESERVED;
        vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-                                    | _PAGE_NO_CACHE);
+                                    | _PAGE_NO_CACHE | _PAGE_GUARDED);
 
        vma->vm_ops = &spufs_signal2_mmap_vmops;
        return 0;
@@ -850,7 +850,7 @@ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
 
        vma->vm_flags |= VM_RESERVED;
        vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-                                    | _PAGE_NO_CACHE);
+                                    | _PAGE_NO_CACHE | _PAGE_GUARDED);
 
        vma->vm_ops = &spufs_mss_mmap_vmops;
        return 0;
@@ -899,7 +899,7 @@ static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
 
        vma->vm_flags |= VM_RESERVED;
        vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-                                    | _PAGE_NO_CACHE);
+                                    | _PAGE_NO_CACHE | _PAGE_GUARDED);
 
        vma->vm_ops = &spufs_mfc_mmap_vmops;
        return 0;
index 3068b429b031149ce8e4a4741bd9a29a3f52c1ec..c7fea2cca5346fbbd675233bc2506fd1adc9576b 100644 (file)
@@ -464,7 +464,8 @@ static inline void wait_purge_complete(struct spu_state *csa, struct spu *spu)
         *     Poll MFC_CNTL[Ps] until value '11' is read
         *     (purge complete).
         */
-       POLL_WHILE_FALSE(in_be64(&priv2->mfc_control_RW) &
+       POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) &
+                        MFC_CNTL_PURGE_DMA_STATUS_MASK) ==
                         MFC_CNTL_PURGE_DMA_COMPLETE);
 }
 
@@ -1028,7 +1029,8 @@ static inline void wait_suspend_mfc_complete(struct spu_state *csa,
         * Restore, Step 47.
         *     Poll MFC_CNTL[Ss] until 11 is returned.
         */
-       POLL_WHILE_FALSE(in_be64(&priv2->mfc_control_RW) &
+       POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) &
+                        MFC_CNTL_SUSPEND_DMA_STATUS_MASK) ==
                         MFC_CNTL_SUSPEND_COMPLETE);
 }
 
@@ -2203,7 +2205,7 @@ void spu_init_csa(struct spu_state *csa)
 
        memset(lscsa, 0, sizeof(struct spu_lscsa));
        csa->lscsa = lscsa;
-       csa->register_lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&csa->register_lock);
 
        /* Set LS pages reserved to allow for user-space mapping. */
        for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
index ac224876ce5943f999a0def0007f7214cd35ff9a..53515daf01b18196ab671f56b485330247833807 100644 (file)
@@ -143,7 +143,7 @@ hydra_init(void)
        if (np == NULL || of_address_to_resource(np, 0, &r))
                return 0;
        Hydra = ioremap(r.start, r.end-r.start);
-       printk("Hydra Mac I/O at %lx\n", r.start);
+       printk("Hydra Mac I/O at %llx\n", (unsigned long long)r.start);
        printk("Hydra Feature_Control was %x",
               in_le32(&Hydra->Feature_Control));
        out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
@@ -267,7 +267,7 @@ chrp_find_bridges(void)
                               bus_range[0], bus_range[1]);
                printk(" controlled by %s", dev->type);
                if (!is_longtrail)
-                       printk(" at %lx", r.start);
+                       printk(" at %llx", (unsigned long long)r.start);
                printk("\n");
 
                hose = pcibios_alloc_controller();
index 4fdbc9ae876b495d05edcc906276eaa4a7625d86..ba07a9a7c0398718f91e61d3e4c037dd9ae83503 100644 (file)
@@ -74,6 +74,16 @@ config SANDPOINT
          Select SANDPOINT if configuring for a Motorola Sandpoint X3
          (any flavor).
 
+config MPC7448HPC2
+       bool "Freescale MPC7448HPC2(Taiga)"
+       select TSI108_BRIDGE
+       select DEFAULT_UIMAGE
+       select PPC_UDBG_16550
+       select MPIC
+       help
+         Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga)
+         platform
+
 config RADSTONE_PPC7D
        bool "Radstone Technology PPC7D board"
        select PPC_I8259
@@ -221,6 +231,11 @@ config MV64X60
        select PPC_INDIRECT_PCI
        default y
 
+config TSI108_BRIDGE
+       bool
+       depends on MPC7448HPC2
+       default y
+
 menu "Set bridge options"
        depends on MV64X60
 
diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile
new file mode 100644 (file)
index 0000000..fa499fe
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Makefile for the 6xx/7xx/7xxxx linux kernel.
+#
+obj-$(CONFIG_MPC7448HPC2)      += mpc7448_hpc2.o
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
new file mode 100644 (file)
index 0000000..d7a4fc7
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * mpc7448_hpc2.c
+ *
+ * Board setup routines for the Freescale Taiga platform
+ *
+ * Author: Jacob Pan
+ *      jacob.pan@freescale.com
+ * Author: Xianghua Xiao
+ *       x.xiao@freescale.com
+ * Maintainer: Roy Zang <tie-fei.zang@freescale.com>
+ *     Add Flat Device Tree support fot mpc7448hpc2 board
+ *
+ * Copyright 2004-2006 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/tsi108.h>
+#include <asm/pci-bridge.h>
+#include <asm/reg.h>
+#include <mm/mmu_decl.h>
+#include "mpc7448_hpc2.h"
+#include <asm/tsi108_irq.h>
+#include <asm/mpic.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+#ifndef CONFIG_PCI
+isa_io_base = MPC7448_HPC2_ISA_IO_BASE;
+isa_mem_base = MPC7448_HPC2_ISA_MEM_BASE;
+pci_dram_offset = MPC7448_HPC2_PCI_MEM_OFFSET;
+#endif
+
+extern int tsi108_setup_pci(struct device_node *dev);
+extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
+extern void tsi108_pci_int_init(void);
+extern int tsi108_irq_cascade(struct pt_regs *regs, void *unused);
+
+/*
+ * Define all of the IRQ senses and polarities.  Taken from the
+ * mpc7448hpc  manual.
+ * Note:  Likely, this table and the following function should be
+ *        obtained and derived from the OF Device Tree.
+ */
+
+static u_char mpc7448_hpc2_pic_initsenses[] __initdata = {
+       /* External on-board sources */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* INT[0] XINT0 from FPGA */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* INT[1] XINT1 from FPGA */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* INT[2] PHY_INT from both GIGE */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* INT[3] RESERVED */
+       /* Internal Tsi108/109 interrupt sources */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* Reserved IRQ */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* Reserved IRQ */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* Reserved IRQ */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* Reserved IRQ */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* DMA0 */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* DMA1 */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* DMA2 */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* DMA3 */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* UART0 */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* UART1 */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* I2C */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* GPIO */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* GIGE0 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* GIGE1 */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* Reserved IRQ */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* HLP */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* SDC */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* Processor IF */
+       (IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),      /* Reserved IRQ */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* PCI/X block */
+};
+
+int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn)
+{
+       if (bus == 0 && PCI_SLOT(devfn) == 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       else
+               return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * find pci slot by devfn in interrupt map of OF tree
+ */
+u8 find_slot_by_devfn(unsigned int *interrupt_map, unsigned int devfn)
+{
+       int i;
+       unsigned int tmp;
+       for (i = 0; i < 4; i++){
+               tmp = interrupt_map[i*4*7];
+               if ((tmp >> 11) == (devfn >> 3))
+                       return i;
+       }
+       return i;
+}
+
+/*
+ * Scans the interrupt map for pci device
+ */
+void mpc7448_hpc2_fixup_irq(struct pci_dev *dev)
+{
+       struct pci_controller *hose;
+       struct device_node *node;
+       unsigned int *interrupt;
+       int busnr;
+       int len;
+       u8 slot;
+       u8 pin;
+
+       /* Lookup the hose */
+       busnr = dev->bus->number;
+       hose = pci_bus_to_hose(busnr);
+       if (!hose)
+               printk(KERN_ERR "No pci hose found\n");
+
+       /* Check it has an OF node associated */
+       node = (struct device_node *) hose->arch_data;
+       if (!node)
+               printk(KERN_ERR "No pci node found\n");
+
+       interrupt = (unsigned int *) get_property(node, "interrupt-map", &len);
+       slot = find_slot_by_devfn(interrupt, dev->devfn);
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       if (pin == 0 || pin > 4)
+               pin = 1;
+       pin--;
+       dev->irq  = interrupt[slot*4*7 + pin*7 + 5];
+       DBG("TSI_PCI: dev->irq = 0x%x\n", dev->irq);
+}
+/* temporary pci irq map fixup*/
+
+void __init mpc7448_hpc2_pcibios_fixup(void)
+{
+       struct pci_dev *dev = NULL;
+       for_each_pci_dev(dev) {
+               mpc7448_hpc2_fixup_irq(dev);
+               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+       }
+}
+
+static void __init mpc7448_hpc2_setup_arch(void)
+{
+       struct device_node *cpu;
+       struct device_node *np;
+       if (ppc_md.progress)
+               ppc_md.progress("mpc7448_hpc2_setup_arch():set_bridge", 0);
+
+       cpu = of_find_node_by_type(NULL, "cpu");
+       if (cpu != 0) {
+               unsigned int *fp;
+
+               fp = (int *)get_property(cpu, "clock-frequency", NULL);
+               if (fp != 0)
+                       loops_per_jiffy = *fp / HZ;
+               else
+                       loops_per_jiffy = 50000000 / HZ;
+               of_node_put(cpu);
+       }
+       tsi108_csr_vir_base = get_vir_csrbase();
+
+#ifdef CONFIG_ROOT_NFS
+       ROOT_DEV = Root_NFS;
+#else
+       ROOT_DEV = Root_HDA1;
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       ROOT_DEV = Root_RAM0;
+#endif
+
+       /* setup PCI host bridge */
+#ifdef CONFIG_PCI
+       for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+               tsi108_setup_pci(np);
+
+       ppc_md.pci_exclude_device = mpc7448_hpc2_exclude_device;
+       if (ppc_md.progress)
+               ppc_md.progress("tsi108: resources set", 0x100);
+#endif
+
+       printk(KERN_INFO "MPC7448HPC2 (TAIGA) Platform\n");
+       printk(KERN_INFO
+              "Jointly ported by Freescale and Tundra Semiconductor\n");
+       printk(KERN_INFO
+              "Enabling L2 cache then enabling the HID0 prefetch engine.\n");
+}
+
+/*
+ * Interrupt setup and service.  Interrrupts on the mpc7448_hpc2 come
+ * from the four external INT pins, PCI interrupts are routed via
+ * PCI interrupt control registers, it generates internal IRQ23
+ *
+ * Interrupt routing on the Taiga Board:
+ * TSI108:PB_INT[0] -> CPU0:INT#
+ * TSI108:PB_INT[1] -> CPU0:MCP#
+ * TSI108:PB_INT[2] -> N/C
+ * TSI108:PB_INT[3] -> N/C
+ */
+static void __init mpc7448_hpc2_init_IRQ(void)
+{
+       struct mpic *mpic;
+       phys_addr_t mpic_paddr = 0;
+       struct device_node *tsi_pic;
+
+       tsi_pic = of_find_node_by_type(NULL, "open-pic");
+       if (tsi_pic) {
+               unsigned int size;
+               void *prop = get_property(tsi_pic, "reg", &size);
+               mpic_paddr = of_translate_address(tsi_pic, prop);
+       }
+
+       if (mpic_paddr == 0) {
+               printk("%s: No tsi108 PIC found !\n", __FUNCTION__);
+               return;
+       }
+
+       DBG("%s: tsi108pic phys_addr = 0x%x\n", __FUNCTION__,
+           (u32) mpic_paddr);
+
+       mpic = mpic_alloc(mpic_paddr,
+                       MPIC_PRIMARY | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET |
+                       MPIC_SPV_EOI | MPIC_MOD_ID(MPIC_ID_TSI108),
+                       0, /* num_sources used */
+                       TSI108_IRQ_BASE,
+                       0, /* num_sources used */
+                       NR_IRQS - 4 /* XXXX */,
+                       mpc7448_hpc2_pic_initsenses,
+                       sizeof(mpc7448_hpc2_pic_initsenses), "Tsi108_PIC");
+
+       BUG_ON(mpic == NULL); /* XXXX */
+
+       mpic_init(mpic);
+       mpic_setup_cascade(IRQ_TSI108_PCI, tsi108_irq_cascade, mpic);
+       tsi108_pci_int_init();
+
+       /* Configure MPIC outputs to CPU0 */
+       tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0);
+}
+
+void mpc7448_hpc2_show_cpuinfo(struct seq_file *m)
+{
+       seq_printf(m, "vendor\t\t: Freescale Semiconductor\n");
+       seq_printf(m, "machine\t\t: MPC7448hpc2\n");
+}
+
+void mpc7448_hpc2_restart(char *cmd)
+{
+       local_irq_disable();
+
+       /* Set exception prefix high - to the firmware */
+       _nmask_and_or_msr(0, MSR_IP);
+
+       for (;;) ;              /* Spin until reset happens */
+}
+
+void mpc7448_hpc2_power_off(void)
+{
+       local_irq_disable();
+       for (;;) ;              /* No way to shut power off with software */
+}
+
+void mpc7448_hpc2_halt(void)
+{
+       mpc7448_hpc2_power_off();
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mpc7448_hpc2_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (!of_flat_dt_is_compatible(root, "mpc74xx"))
+               return 0;
+       return 1;
+}
+
+static int mpc7448_machine_check_exception(struct pt_regs *regs)
+{
+       extern void tsi108_clear_pci_cfg_error(void);
+       const struct exception_table_entry *entry;
+
+       /* Are we prepared to handle this fault */
+       if ((entry = search_exception_tables(regs->nip)) != NULL) {
+               tsi108_clear_pci_cfg_error();
+               regs->msr |= MSR_RI;
+               regs->nip = entry->fixup;
+               return 1;
+       }
+       return 0;
+
+}
+define_machine(mpc7448_hpc2){
+       .name                   = "MPC7448 HPC2",
+       .probe                  = mpc7448_hpc2_probe,
+       .setup_arch             = mpc7448_hpc2_setup_arch,
+       .init_IRQ               = mpc7448_hpc2_init_IRQ,
+       .show_cpuinfo           = mpc7448_hpc2_show_cpuinfo,
+       .get_irq                = mpic_get_irq,
+       .pcibios_fixup          = mpc7448_hpc2_pcibios_fixup,
+       .restart                = mpc7448_hpc2_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .machine_check_exception= mpc7448_machine_check_exception,
+       .progress               = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h
new file mode 100644 (file)
index 0000000..a543a52
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * mpc7448_hpc2.h
+ *
+ * Definitions for Freescale MPC7448_HPC2 platform
+ *
+ * Author: Jacob Pan
+ *         jacob.pan@freescale.com
+ * Maintainer: Roy Zang <roy.zang@freescale.com>
+ *
+ * 2006 (c) Freescale Semiconductor, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __PPC_PLATFORMS_MPC7448_HPC2_H
+#define __PPC_PLATFORMS_MPC7448_HPC2_H
+
+#include <asm/ppcboot.h>
+
+/* Base Addresses for the PCI bus
+ */
+#define MPC7448_HPC2_PCI_MEM_OFFSET    (0x00000000)
+#define MPC7448_HPC2_ISA_IO_BASE       (0x00000000)
+#define MPC7448_HPC2_ISA_MEM_BASE      (0x00000000)
+#endif                         /* __PPC_PLATFORMS_MPC7448_HPC2_H */
index d3444aabe76e46bdda0cd6832cb56a480fe6095f..d194140c1ebf083cba4dc24e133f46b09c672143 100644 (file)
@@ -252,6 +252,7 @@ static void __init dt_model(struct iseries_flat_dt *dt)
 {
        char buf[16] = "IBM,";
 
+       /* N.B. lparcfg.c knows about the "IBM," prefixes ... */
        /* "IBM," + mfgId[2:3] + systemSerial[1:5] */
        strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2);
        strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5);
@@ -264,6 +265,7 @@ static void __init dt_model(struct iseries_flat_dt *dt)
        dt_prop_str(dt, "model", buf);
 
        dt_prop_str(dt, "compatible", "IBM,iSeries");
+       dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex());
 }
 
 static void __init dt_do_vdevice(struct iseries_flat_dt *dt,
index 30bdcf3925d9b1727cc37a82c48582c06eff6f30..ed44dfceaa45069f016ba6a809d0c3c2cf3cf4d9 100644 (file)
@@ -242,13 +242,11 @@ static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va,
        local_irq_restore(flags);
 }
 
-void hpte_init_iSeries(void)
+void __init hpte_init_iSeries(void)
 {
        ppc_md.hpte_invalidate  = iSeries_hpte_invalidate;
        ppc_md.hpte_updatepp    = iSeries_hpte_updatepp;
        ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp;
        ppc_md.hpte_insert      = iSeries_hpte_insert;
        ppc_md.hpte_remove      = iSeries_hpte_remove;
-
-       htab_finish_init();
 }
index 62bbbcf5ded3e27d19f5c2ed0f1d2e402171b87f..33bb4aa0e1e819df8464376de3064b48622f76b1 100644 (file)
@@ -242,9 +242,9 @@ void __init iSeries_activate_IRQs()
        for_each_irq (irq) {
                irq_desc_t *desc = get_irq_desc(irq);
 
-               if (desc && desc->handler && desc->handler->startup) {
+               if (desc && desc->chip && desc->chip->startup) {
                        spin_lock_irqsave(&desc->lock, flags);
-                       desc->handler->startup(irq);
+                       desc->chip->startup(irq);
                        spin_unlock_irqrestore(&desc->lock, flags);
                }
        }
@@ -324,7 +324,7 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus,
                + function;
        virtirq = virt_irq_create_mapping(realirq);
 
-       irq_desc[virtirq].handler = &iSeries_IRQ_handler;
+       irq_desc[virtirq].chip = &iSeries_IRQ_handler;
        return virtirq;
 }
 
index 8ca7b939635574c5079513060ce4d6657cf985f8..2a9f81ea27d6b0ab2bb8933ff7f20ada4c82d35b 100644 (file)
@@ -51,20 +51,21 @@ static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes];
 static struct HvLpEvent * get_next_hvlpevent(void)
 {
        struct HvLpEvent * event;
-       event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr;
+       event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event;
 
        if (hvlpevent_is_valid(event)) {
                /* rmb() needed only for weakly consistent machines (regatta) */
                rmb();
                /* Set pointer to next potential event */
-               hvlpevent_queue.xSlicCurEventPtr += ((event->xSizeMinus1 +
-                               LpEventAlign) / LpEventAlign) * LpEventAlign;
+               hvlpevent_queue.hq_current_event += ((event->xSizeMinus1 +
+                               IT_LP_EVENT_ALIGN) / IT_LP_EVENT_ALIGN) *
+                                       IT_LP_EVENT_ALIGN;
 
                /* Wrap to beginning if no room at end */
-               if (hvlpevent_queue.xSlicCurEventPtr >
-                               hvlpevent_queue.xSlicLastValidEventPtr) {
-                       hvlpevent_queue.xSlicCurEventPtr =
-                               hvlpevent_queue.xSlicEventStackPtr;
+               if (hvlpevent_queue.hq_current_event >
+                               hvlpevent_queue.hq_last_event) {
+                       hvlpevent_queue.hq_current_event =
+                               hvlpevent_queue.hq_event_stack;
                }
        } else {
                event = NULL;
@@ -82,10 +83,10 @@ int hvlpevent_is_pending(void)
        if (smp_processor_id() >= spread_lpevents)
                return 0;
 
-       next_event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr;
+       next_event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event;
 
        return hvlpevent_is_valid(next_event) ||
-               hvlpevent_queue.xPlicOverflowIntPending;
+               hvlpevent_queue.hq_overflow_pending;
 }
 
 static void hvlpevent_clear_valid(struct HvLpEvent * event)
@@ -95,18 +96,18 @@ static void hvlpevent_clear_valid(struct HvLpEvent * event)
         * ie. on 64-byte boundaries.
         */
        struct HvLpEvent *tmp;
-       unsigned extra = ((event->xSizeMinus1 + LpEventAlign) /
-                                                LpEventAlign) - 1;
+       unsigned extra = ((event->xSizeMinus1 + IT_LP_EVENT_ALIGN) /
+                               IT_LP_EVENT_ALIGN) - 1;
 
        switch (extra) {
        case 3:
-               tmp = (struct HvLpEvent*)((char*)event + 3 * LpEventAlign);
+               tmp = (struct HvLpEvent*)((char*)event + 3 * IT_LP_EVENT_ALIGN);
                hvlpevent_invalidate(tmp);
        case 2:
-               tmp = (struct HvLpEvent*)((char*)event + 2 * LpEventAlign);
+               tmp = (struct HvLpEvent*)((char*)event + 2 * IT_LP_EVENT_ALIGN);
                hvlpevent_invalidate(tmp);
        case 1:
-               tmp = (struct HvLpEvent*)((char*)event + 1 * LpEventAlign);
+               tmp = (struct HvLpEvent*)((char*)event + 1 * IT_LP_EVENT_ALIGN);
                hvlpevent_invalidate(tmp);
        }
 
@@ -120,7 +121,7 @@ void process_hvlpevents(struct pt_regs *regs)
        struct HvLpEvent * event;
 
        /* If we have recursed, just return */
-       if (!spin_trylock(&hvlpevent_queue.lock))
+       if (!spin_trylock(&hvlpevent_queue.hq_lock))
                return;
 
        for (;;) {
@@ -148,17 +149,17 @@ void process_hvlpevents(struct pt_regs *regs)
                                printk(KERN_INFO "Unexpected Lp Event type=%d\n", event->xType );
 
                        hvlpevent_clear_valid(event);
-               } else if (hvlpevent_queue.xPlicOverflowIntPending)
+               } else if (hvlpevent_queue.hq_overflow_pending)
                        /*
                         * No more valid events. If overflow events are
                         * pending process them
                         */
-                       HvCallEvent_getOverflowLpEvents(hvlpevent_queue.xIndex);
+                       HvCallEvent_getOverflowLpEvents(hvlpevent_queue.hq_index);
                else
                        break;
        }
 
-       spin_unlock(&hvlpevent_queue.lock);
+       spin_unlock(&hvlpevent_queue.hq_lock);
 }
 
 static int set_spread_lpevents(char *str)
@@ -184,20 +185,20 @@ void setup_hvlpevent_queue(void)
 {
        void *eventStack;
 
-       spin_lock_init(&hvlpevent_queue.lock);
+       spin_lock_init(&hvlpevent_queue.hq_lock);
 
        /* Allocate a page for the Event Stack. */
-       eventStack = alloc_bootmem_pages(LpEventStackSize);
-       memset(eventStack, 0, LpEventStackSize);
+       eventStack = alloc_bootmem_pages(IT_LP_EVENT_STACK_SIZE);
+       memset(eventStack, 0, IT_LP_EVENT_STACK_SIZE);
 
        /* Invoke the hypervisor to initialize the event stack */
-       HvCallEvent_setLpEventStack(0, eventStack, LpEventStackSize);
+       HvCallEvent_setLpEventStack(0, eventStack, IT_LP_EVENT_STACK_SIZE);
 
-       hvlpevent_queue.xSlicEventStackPtr = (char *)eventStack;
-       hvlpevent_queue.xSlicCurEventPtr = (char *)eventStack;
-       hvlpevent_queue.xSlicLastValidEventPtr = (char *)eventStack +
-                                       (LpEventStackSize - LpEventMaxSize);
-       hvlpevent_queue.xIndex = 0;
+       hvlpevent_queue.hq_event_stack = eventStack;
+       hvlpevent_queue.hq_current_event = eventStack;
+       hvlpevent_queue.hq_last_event = (char *)eventStack +
+               (IT_LP_EVENT_STACK_SIZE - IT_LP_EVENT_MAX_SIZE);
+       hvlpevent_queue.hq_index = 0;
 }
 
 /* Register a handler for an LpEvent type */
index e68b6b5fa89f0b0e20446af206779af6e8d632f4..c241413629ac155266cb7fcddb8fa68da759a3c6 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/processor.h>
 #include <asm/time.h>
 #include <asm/lppaca.h>
-#include <asm/iseries/it_lp_queue.h>
 #include <asm/iseries/hv_call_xm.h>
 
 #include "processor_vpd.h"
index 617c724c4590841df47f43e1512743db0d155f62..66c77e4f8ec2441c932d30f26db8a5d1e3e209ce 100644 (file)
@@ -81,8 +81,6 @@ static void iSeries_pci_final_fixup(void) { }
 #endif
 
 extern int rd_size;            /* Defined in drivers/block/rd.c */
-extern unsigned long embedded_sysmap_start;
-extern unsigned long embedded_sysmap_end;
 
 extern unsigned long iSeries_recal_tb;
 extern unsigned long iSeries_recal_titan;
@@ -320,11 +318,6 @@ static void __init iSeries_init_early(void)
        iSeries_recal_tb = get_tb();
        iSeries_recal_titan = HvCallXm_loadTod();
 
-       /*
-        * Initialize the hash table management pointers
-        */
-       hpte_init_iSeries();
-
        /*
         * Initialize the DMA/TCE management
         */
@@ -563,16 +556,6 @@ static void __init iSeries_fixup_klimit(void)
        if (naca.xRamDisk)
                klimit = KERNELBASE + (u64)naca.xRamDisk +
                        (naca.xRamDiskSize * HW_PAGE_SIZE);
-       else {
-               /*
-                * No ram disk was included - check and see if there
-                * was an embedded system map.  Change klimit to take
-                * into account any embedded system map
-                */
-               if (embedded_sysmap_end)
-                       klimit = KERNELBASE + ((embedded_sysmap_end + 4095) &
-                                       0xfffffffffffff000);
-       }
 }
 
 static int __init iSeries_src_init(void)
@@ -683,6 +666,8 @@ static int __init iseries_probe(void)
         */
        virt_irq_max = 255;
 
+       hpte_init_iSeries();
+
        return 1;
 }
 
index 9a4efc0c3b2932f025275287f9c42f4f94f30ad9..f7170ff86dab2d04cc1c0e7ec0b235c1684b1cee 100644 (file)
@@ -376,9 +376,10 @@ static void __init maple_fixup_phb_resources(void)
                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",
+               printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n",
                       hose->global_number,
-                      hose->io_resource.start, hose->io_resource.end);
+                      (unsigned long long)hose->io_resource.start,
+                      (unsigned long long)hose->io_resource.end);
        }
 }
 
index a0505ea48a86ca75343206829d06fb0e361920c6..4e32a5417fd14897e17cf1bf69ae3fa6b5c43ed0 100644 (file)
@@ -199,11 +199,6 @@ static void __init maple_init_early(void)
 {
        DBG(" -> maple_init_early\n");
 
-       /* Initialize hash table, from now on, we can take hash faults
-        * and call ioremap
-        */
-       hpte_init_native();
-
        /* Setup interrupt mapping options */
        ppc64_interrupt_controller = IC_OPEN_PIC;
 
@@ -272,6 +267,8 @@ static int __init maple_probe(void)
         */
        alloc_dart_table();
 
+       hpte_init_native();
+
        return 1;
 }
 
index 498b042e1837567c2326c93faa404d6ffa6a4d00..c7a27eddca6d4b96f002f2c5b5a3725933849089 100644 (file)
@@ -119,7 +119,14 @@ int pmac_backlight_set_legacy_brightness(int brightness)
                down(&pmac_backlight->sem);
                props = pmac_backlight->props;
                props->brightness = brightness *
-                       props->max_brightness / OLD_BACKLIGHT_MAX;
+                       (props->max_brightness + 1) /
+                       (OLD_BACKLIGHT_MAX + 1);
+
+               if (props->brightness > props->max_brightness)
+                       props->brightness = props->max_brightness;
+               else if (props->brightness < 0)
+                       props->brightness = 0;
+
                props->update_status(pmac_backlight);
                up(&pmac_backlight->sem);
 
@@ -140,8 +147,11 @@ int pmac_backlight_get_legacy_brightness()
 
                down(&pmac_backlight->sem);
                props = pmac_backlight->props;
+
                result = props->brightness *
-                       OLD_BACKLIGHT_MAX / props->max_brightness;
+                       (OLD_BACKLIGHT_MAX + 1) /
+                       (props->max_brightness + 1);
+
                up(&pmac_backlight->sem);
        }
        mutex_unlock(&pmac_backlight_mutex);
index 80035853467b000fa1517920762b8bc1bfdfef8b..d524a915aa8646e19080d32d90b8c6292ddcefd0 100644 (file)
@@ -939,9 +939,10 @@ static int __init add_bridge(struct device_node *dev)
                disp_name = "Chaos";
                primary = 0;
        }
-       printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. "
+       printk(KERN_INFO "Found %s PCI host bridge at 0x%016llx. "
               "Firmware bus number: %d->%d\n",
-               disp_name, rsrc.start, hose->first_busno, hose->last_busno);
+               disp_name, (unsigned long long)rsrc.start, hose->first_busno,
+               hose->last_busno);
 #endif /* CONFIG_PPC32 */
 
        DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
index 047f954a89eb933206396688cd45dcf3b28d2a12..93e7505debc59813fb30dc82afadf96b963ef0bc 100644 (file)
@@ -546,7 +546,7 @@ struct pmf_device {
 };
 
 static LIST_HEAD(pmf_devices);
-static spinlock_t pmf_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(pmf_lock);
 static DEFINE_MUTEX(pmf_irq_mutex);
 
 static void pmf_release_device(struct kref *kref)
index 18bf3011d1e3ff103675b0bae793570f4c82606d..9f6189af6dd6b2c5daab9fb1d5d70a3e574ee233 100644 (file)
@@ -446,7 +446,7 @@ static void __init pmac_pic_probe_oldstyle(void)
 
        /* Set the handler for the main PIC */
        for ( i = 0; i < max_real_irqs ; i++ )
-               irq_desc[i].handler = &pmac_pic;
+               irq_desc[i].chip = &pmac_pic;
 
        /* Get addresses of first controller if we have a node for it */
        BUG_ON(of_address_to_resource(master, 0, &r));
@@ -493,7 +493,7 @@ static void __init pmac_pic_probe_oldstyle(void)
        /* Setup handlers for secondary controller and hook cascade irq*/
        if (slave) {
                for ( i = max_real_irqs ; i < max_irqs ; i++ )
-                       irq_desc[i].handler = &gatwick_pic;
+                       irq_desc[i].chip = &gatwick_pic;
                setup_irq(irq_cascade, &gatwick_cascade_action);
        }
        printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);
index 9cc7db7a8bdc443a1da0af1cb4adf34ad7b462af..89c5775f83beffb4947fb5c466bb6478096e84e4 100644 (file)
@@ -600,13 +600,6 @@ pmac_halt(void)
  */
 static void __init pmac_init_early(void)
 {
-#ifdef CONFIG_PPC64
-       /* Initialize hash table, from now on, we can take hash faults
-        * and call ioremap
-        */
-       hpte_init_native();
-#endif
-
        /* Enable early btext debug if requested */
        if (strstr(cmd_line, "btextdbg")) {
                udbg_adb_init_early();
@@ -683,6 +676,8 @@ static int __init pmac_probe(void)
         * part of the cacheable linar mapping
         */
        alloc_dart_table();
+
+       hpte_init_native();
 #endif
 
 #ifdef CONFIG_PPC32
index 8f2d12935b99fe47de2a273ad4b12338fbcb5f4f..45ccc687e57cbedc3395f0c113b7117a5c6c1b53 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 /* EEH event workqueue setup. */
-static spinlock_t eeh_eventlist_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(eeh_eventlist_lock);
 LIST_HEAD(eeh_eventlist);
 static void eeh_thread_launcher(void *);
 DECLARE_WORK(eeh_event_wq, eeh_thread_launcher, NULL);
index d03a8b078f9db09ffa72cffbd01cba8aa4cc8413..8cfb5706790ecd395bd7039463a435a6a0574405 100644 (file)
@@ -92,6 +92,15 @@ static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages)
                *(tcep++) = 0;
 }
 
+static unsigned long tce_get_pseries(struct iommu_table *tbl, long index)
+{
+       u64 *tcep;
+
+       index <<= TCE_PAGE_FACTOR;
+       tcep = ((u64 *)tbl->it_base) + index;
+
+       return *tcep;
+}
 
 static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
                                long npages, unsigned long uaddr,
@@ -235,6 +244,25 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n
        }
 }
 
+static unsigned long tce_get_pSeriesLP(struct iommu_table *tbl, long tcenum)
+{
+       u64 rc;
+       unsigned long tce_ret;
+
+       tcenum <<= TCE_PAGE_FACTOR;
+       rc = plpar_tce_get((u64)tbl->it_index, (u64)tcenum << 12, &tce_ret);
+
+       if (rc && printk_ratelimit()) {
+               printk("tce_get_pSeriesLP: plpar_tce_get failed. rc=%ld\n",
+                       rc);
+               printk("\tindex   = 0x%lx\n", (u64)tbl->it_index);
+               printk("\ttcenum  = 0x%lx\n", (u64)tcenum);
+               show_stack(current, (unsigned long *)__get_SP());
+       }
+
+       return tce_ret;
+}
+
 static void iommu_table_setparms(struct pci_controller *phb,
                                 struct device_node *dn,
                                 struct iommu_table *tbl)
@@ -254,7 +282,10 @@ static void iommu_table_setparms(struct pci_controller *phb,
        }
 
        tbl->it_base = (unsigned long)__va(*basep);
+
+#ifndef CONFIG_CRASH_DUMP
        memset((void *)tbl->it_base, 0, *sizep);
+#endif
 
        tbl->it_busno = phb->bus->number;
 
@@ -560,11 +591,13 @@ void iommu_init_early_pSeries(void)
                        ppc_md.tce_build = tce_build_pSeriesLP;
                        ppc_md.tce_free  = tce_free_pSeriesLP;
                }
+               ppc_md.tce_get   = tce_get_pSeriesLP;
                ppc_md.iommu_bus_setup = iommu_bus_setup_pSeriesLP;
                ppc_md.iommu_dev_setup = iommu_dev_setup_pSeriesLP;
        } else {
                ppc_md.tce_build = tce_build_pSeries;
                ppc_md.tce_free  = tce_free_pSeries;
+               ppc_md.tce_get   = tce_get_pseries;
                ppc_md.iommu_bus_setup = iommu_bus_setup_pSeries;
                ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries;
        }
index 634b7d06d3cc2a7df78645104294fae0e491647a..27480705996f988ae6335925930bb08911afa173 100644 (file)
@@ -513,7 +513,7 @@ void pSeries_lpar_flush_hash_range(unsigned long number, int local)
                spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);
 }
 
-void hpte_init_lpar(void)
+void __init hpte_init_lpar(void)
 {
        ppc_md.hpte_invalidate  = pSeries_lpar_hpte_invalidate;
        ppc_md.hpte_updatepp    = pSeries_lpar_hpte_updatepp;
@@ -522,6 +522,4 @@ void hpte_init_lpar(void)
        ppc_md.hpte_remove      = pSeries_lpar_hpte_remove;
        ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range;
        ppc_md.hpte_clear_all   = pSeries_lpar_hptab_clear;
-
-       htab_finish_init();
 }
index 1e28518c6121f7431526b75501ff15aa3d9e0ef4..b3197ff156c6ab277b46abe710eb8fbc0a6c18e4 100644 (file)
@@ -322,11 +322,6 @@ static void __init pSeries_init_early(void)
        DBG(" -> pSeries_init_early()\n");
 
        fw_feature_init();
-       
-       if (firmware_has_feature(FW_FEATURE_LPAR))
-               hpte_init_lpar();
-       else
-               hpte_init_native();
 
        if (firmware_has_feature(FW_FEATURE_LPAR))
                find_udbg_vterm();
@@ -384,6 +379,11 @@ static int __init pSeries_probe_hypertas(unsigned long node,
        if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
                powerpc_firmware_features |= FW_FEATURE_LPAR;
 
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               hpte_init_lpar();
+       else
+               hpte_init_native();
+
        return 1;
 }
 
index b14f9b5c114edebf110120973e8fe43b4fa1168e..19c03dd43000fdd46c31413da79e7a11d7e5397c 100644 (file)
@@ -238,7 +238,7 @@ static int get_irq_server(unsigned int irq)
 {
        unsigned int server;
        /* For the moment only implement delivery to all cpus or one cpu */
-       cpumask_t cpumask = irq_affinity[irq];
+       cpumask_t cpumask = irq_desc[irq].affinity;
        cpumask_t tmp = CPU_MASK_NONE;
 
        if (!distribute_irqs)
@@ -558,7 +558,7 @@ nextnode:
        }
 
        for (i = irq_offset_value(); i < NR_IRQS; ++i)
-               get_irq_desc(i)->handler = &xics_pic;
+               get_irq_desc(i)->chip = &xics_pic;
 
        xics_setup_cpu();
 
@@ -701,9 +701,9 @@ void xics_migrate_irqs_away(void)
                        continue;
 
                /* We only need to migrate enabled IRQS */
-               if (desc == NULL || desc->handler == NULL
+               if (desc == NULL || desc->chip == NULL
                    || desc->action == NULL
-                   || desc->handler->set_affinity == NULL)
+                   || desc->chip->set_affinity == NULL)
                        continue;
 
                spin_lock_irqsave(&desc->lock, flags);
@@ -728,8 +728,8 @@ void xics_migrate_irqs_away(void)
                       virq, cpu);
 
                /* Reset affinity to all cpus */
-               desc->handler->set_affinity(virq, CPU_MASK_ALL);
-               irq_affinity[virq] = CPU_MASK_ALL;
+               desc->chip->set_affinity(virq, CPU_MASK_ALL);
+               irq_desc[irq].affinity = CPU_MASK_ALL;
 unlock:
                spin_unlock_irqrestore(&desc->lock, flags);
        }
index cef95b023730aefa9aa865a10c4f783bd1c67ce6..054bd8b41ef51d5851c37c47ae0bb6a5513bf056 100644 (file)
@@ -12,3 +12,5 @@ obj-$(CONFIG_U3_DART)         += dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)       += mmio_nvram.o
 obj-$(CONFIG_PPC_83xx)         += ipic.o
 obj-$(CONFIG_FSL_SOC)          += fsl_soc.o
+obj-$(CONFIG_PPC_TODC)         += todc.o
+obj-$(CONFIG_TSI108_BRIDGE)    += tsi108_pci.o tsi108_dev.o
index c2d05763ccbe679b09a24fe57563b4fc1287b956..1c8817c4835ee780dcf5f0e0cc285cd4f790d86f 100644 (file)
 /* U4 registers */
 #define DART_BASE_U4_BASE_MASK 0xffffff
 #define DART_BASE_U4_BASE_SHIFT        0
-#define DART_CNTL_U4_FLUSHTLB  0x20000000
 #define DART_CNTL_U4_ENABLE    0x80000000
+#define DART_CNTL_U4_IONE      0x40000000
+#define DART_CNTL_U4_FLUSHTLB  0x20000000
+#define DART_CNTL_U4_IDLE      0x10000000
+#define DART_CNTL_U4_PAR_EN    0x08000000
+#define DART_CNTL_U4_IONE_MASK 0x07ffffff
 #define DART_SIZE_U4_SIZE_MASK 0x1fff
 #define DART_SIZE_U4_SIZE_SHIFT        0
 
index 6232091cc72bcd87b8e6f69c9242257b770926e1..7c7f34ce4986621808f0d5d731f55f9fe19e6711 100644 (file)
@@ -101,8 +101,8 @@ retry:
        if (l == (1L << limit)) {
                if (limit < 4) {
                        limit++;
-                       reg = DART_IN(DART_CNTL);
-                       reg &= ~inv_bit;
+                       reg = DART_IN(DART_CNTL);
+                       reg &= ~inv_bit;
                        DART_OUT(DART_CNTL, reg);
                        goto retry;
                } else
@@ -111,11 +111,39 @@ retry:
        }
 }
 
+static inline void dart_tlb_invalidate_one(unsigned long bus_rpn)
+{
+       unsigned int reg;
+       unsigned int l, limit;
+
+       reg = DART_CNTL_U4_ENABLE | DART_CNTL_U4_IONE |
+               (bus_rpn & DART_CNTL_U4_IONE_MASK);
+       DART_OUT(DART_CNTL, reg);
+
+       limit = 0;
+wait_more:
+       l = 0;
+       while ((DART_IN(DART_CNTL) & DART_CNTL_U4_IONE) && l < (1L << limit)) {
+               rmb();
+               l++;
+       }
+
+       if (l == (1L << limit)) {
+               if (limit < 4) {
+                       limit++;
+                       goto wait_more;
+               } else
+                       panic("DART: TLB did not flush after waiting a long "
+                             "time. Buggy U4 ?");
+       }
+}
+
 static void dart_flush(struct iommu_table *tbl)
 {
-       if (dart_dirty)
+       if (dart_dirty) {
                dart_tlb_invalidate_all();
-       dart_dirty = 0;
+               dart_dirty = 0;
+       }
 }
 
 static void dart_build(struct iommu_table *tbl, long index,
@@ -124,6 +152,7 @@ static void dart_build(struct iommu_table *tbl, long index,
 {
        unsigned int *dp;
        unsigned int rpn;
+       long l;
 
        DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr);
 
@@ -135,7 +164,8 @@ static void dart_build(struct iommu_table *tbl, long index,
        /* On U3, all memory is contigous, so we can move this
         * out of the loop.
         */
-       while (npages--) {
+       l = npages;
+       while (l--) {
                rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT;
 
                *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK);
@@ -143,7 +173,14 @@ static void dart_build(struct iommu_table *tbl, long index,
                uaddr += DART_PAGE_SIZE;
        }
 
-       dart_dirty = 1;
+       if (dart_is_u4) {
+               rpn = index;
+               mb(); /* make sure all updates have reached memory */
+               while (npages--)
+                       dart_tlb_invalidate_one(rpn++);
+       } else {
+               dart_dirty = 1;
+       }
 }
 
 
index b7ac32fdd7766f74ceff0d2098df4614eae83701..2bff30f6d6357aa4b44a8bba2ae7ec17d2d17fcd 100644 (file)
@@ -208,7 +208,7 @@ void __init i8259_init(unsigned long intack_addr, int offset)
        spin_unlock_irqrestore(&i8259_lock, flags);
 
        for (i = 0; i < NUM_ISA_INTERRUPTS; ++i)
-               irq_desc[offset + i].handler = &i8259_pic;
+               irq_desc[offset + i].chip = &i8259_pic;
 
        /* reserve our resources */
        setup_irq(offset + 2, &i8259_irqaction);
index 8f01e0f1d847404ceea8ce035f390c1fa2091f6c..46801f5ec03f3883b424239e7a9c13b958ae9144 100644 (file)
@@ -472,7 +472,7 @@ void __init ipic_init(phys_addr_t phys_addr,
        ipic_write(primary_ipic->regs, IPIC_SEMSR, temp);
 
        for (i = 0 ; i < NR_IPIC_INTS ; i++) {
-               irq_desc[i+irq_offset].handler = &ipic;
+               irq_desc[i+irq_offset].chip = &ipic;
                irq_desc[i+irq_offset].status = IRQ_LEVEL;
        }
 
index 74e0d31a3559cf9ca3859a0f3b55fff962966f97..615350d46b526110f55bb0c80f63c7b22e01ffe7 100644 (file)
@@ -32,7 +32,7 @@
 
 static void __iomem *mmio_nvram_start;
 static long mmio_nvram_len;
-static spinlock_t mmio_nvram_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(mmio_nvram_lock);
 
 static ssize_t mmio_nvram_read(char *buf, size_t count, loff_t *index)
 {
index bffe50d02c99578fc75f85055387216ee8a88761..28df9c827ca66b409d0b0427f09c22944dad2079 100644 (file)
@@ -379,14 +379,14 @@ static inline u32 mpic_physmask(u32 cpumask)
 /* 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);
+       return container_of(irq_desc[ipi].chip, 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);
+       return container_of(irq_desc[irq].chip, struct mpic, hc_irq);
 }
 
 /* Send an EOI */
@@ -752,7 +752,7 @@ void __init mpic_init(struct mpic *mpic)
                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;
+               irq_desc[mpic->ipi_offset+i].chip = &mpic->hc_ipi;
 #endif /* CONFIG_SMP */
        }
 
@@ -813,7 +813,7 @@ void __init mpic_init(struct mpic *mpic)
                /* 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;
+                       irq_desc[mpic->irq_offset+i].chip = &mpic->hc_irq;
                }
        }
        
@@ -906,7 +906,7 @@ void mpic_setup_this_cpu(void)
        /* 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.
+        * values of irq_desc[].affinity in irq.c.
         */
        if (distribute_irqs) {
                for (i = 0; i < mpic->num_sources ; i++)
diff --git a/arch/powerpc/sysdev/todc.c b/arch/powerpc/sysdev/todc.c
new file mode 100644 (file)
index 0000000..0a65980
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818
+ * Real Time Clocks/Timekeepers.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2001-2004 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/bcd.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+
+/*
+ * Depending on the hardware on your board and your board design, the
+ * RTC/NVRAM may be accessed either directly (like normal memory) or via
+ * address/data registers.  If your board uses the direct method, set
+ * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and
+ * 'nvram_as1' NULL.  If your board uses address/data regs to access nvram,
+ * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the
+ * address of the upper byte (leave NULL if using mc146818), and set
+ * 'nvram_data' to the address of the 8-bit data register.
+ *
+ * Note: Even though the documentation for the various RTC chips say that it
+ *      take up to a second before it starts updating once the 'R' bit is
+ *      cleared, they always seem to update even though we bang on it many
+ *      times a second.  This is true, except for the Dallas Semi 1746/1747
+ *      (possibly others).  Those chips seem to have a real problem whenever
+ *      we set the 'R' bit before reading them, they basically stop counting.
+ *                                             --MAG
+ */
+
+/*
+ * 'todc_info' should be initialized in your *_setup.c file to
+ * point to a fully initialized 'todc_info_t' structure.
+ * This structure holds all the register offsets for your particular
+ * TODC/RTC chip.
+ * TODC_ALLOC()/TODC_INIT() will allocate and initialize this table for you.
+ */
+
+#ifdef RTC_FREQ_SELECT
+#undef RTC_FREQ_SELECT
+#define        RTC_FREQ_SELECT         control_b       /* Register A */
+#endif
+
+#ifdef RTC_CONTROL
+#undef RTC_CONTROL
+#define        RTC_CONTROL             control_a       /* Register B */
+#endif
+
+#ifdef RTC_INTR_FLAGS
+#undef RTC_INTR_FLAGS
+#define        RTC_INTR_FLAGS          watchdog        /* Register C */
+#endif
+
+#ifdef RTC_VALID
+#undef RTC_VALID
+#define        RTC_VALID               interrupts      /* Register D */
+#endif
+
+/* Access routines when RTC accessed directly (like normal memory) */
+u_char
+todc_direct_read_val(int addr)
+{
+       return readb((void __iomem *)(todc_info->nvram_data + addr));
+}
+
+void
+todc_direct_write_val(int addr, unsigned char val)
+{
+       writeb(val, (void __iomem *)(todc_info->nvram_data + addr));
+       return;
+}
+
+/* Access routines for accessing m48txx type chips via addr/data regs */
+u_char
+todc_m48txx_read_val(int addr)
+{
+       outb(addr, todc_info->nvram_as0);
+       outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
+       return inb(todc_info->nvram_data);
+}
+
+void
+todc_m48txx_write_val(int addr, unsigned char val)
+{
+       outb(addr, todc_info->nvram_as0);
+       outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
+       outb(val, todc_info->nvram_data);
+       return;
+}
+
+/* Access routines for accessing mc146818 type chips via addr/data regs */
+u_char
+todc_mc146818_read_val(int addr)
+{
+       outb_p(addr, todc_info->nvram_as0);
+       return inb_p(todc_info->nvram_data);
+}
+
+void
+todc_mc146818_write_val(int addr, unsigned char val)
+{
+       outb_p(addr, todc_info->nvram_as0);
+       outb_p(val, todc_info->nvram_data);
+}
+
+
+/*
+ * Routines to make RTC chips with NVRAM buried behind an addr/data pair
+ * have the NVRAM and clock regs appear at the same level.
+ * The NVRAM will appear to start at addr 0 and the clock regs will appear
+ * to start immediately after the NVRAM (actually, start at offset
+ * todc_info->nvram_size).
+ */
+static inline u_char
+todc_read_val(int addr)
+{
+       u_char  val;
+
+       if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) {
+               if (addr < todc_info->nvram_size) { /* NVRAM */
+                       ppc_md.rtc_write_val(todc_info->nvram_addr_reg, addr);
+                       val = ppc_md.rtc_read_val(todc_info->nvram_data_reg);
+               } else { /* Clock Reg */
+                       addr -= todc_info->nvram_size;
+                       val = ppc_md.rtc_read_val(addr);
+               }
+       } else
+               val = ppc_md.rtc_read_val(addr);
+
+       return val;
+}
+
+static inline void
+todc_write_val(int addr, u_char val)
+{
+       if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) {
+               if (addr < todc_info->nvram_size) { /* NVRAM */
+                       ppc_md.rtc_write_val(todc_info->nvram_addr_reg, addr);
+                       ppc_md.rtc_write_val(todc_info->nvram_data_reg, val);
+               } else { /* Clock Reg */
+                       addr -= todc_info->nvram_size;
+                       ppc_md.rtc_write_val(addr, val);
+               }
+       } else
+               ppc_md.rtc_write_val(addr, val);
+}
+
+/*
+ * TODC routines
+ *
+ * There is some ugly stuff in that there are assumptions for the mc146818.
+ *
+ * Assumptions:
+ *     - todc_info->control_a has the offset as mc146818 Register B reg
+ *     - todc_info->control_b has the offset as mc146818 Register A reg
+ *     - m48txx control reg's write enable or 'W' bit is same as
+ *       mc146818 Register B 'SET' bit (i.e., 0x80)
+ *
+ * These assumptions were made to make the code simpler.
+ */
+long __init
+todc_time_init(void)
+{
+       u_char  cntl_b;
+
+       if (!ppc_md.rtc_read_val)
+               ppc_md.rtc_read_val = ppc_md.nvram_read_val;
+       if (!ppc_md.rtc_write_val)
+               ppc_md.rtc_write_val = ppc_md.nvram_write_val;
+
+       cntl_b = todc_read_val(todc_info->control_b);
+
+       if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+               if ((cntl_b & 0x70) != 0x20) {
+                       printk(KERN_INFO "TODC real-time-clock was stopped."
+                               "  Now starting...");
+                       cntl_b &= ~0x70;
+                       cntl_b |= 0x20;
+               }
+
+               todc_write_val(todc_info->control_b, cntl_b);
+       } else if (todc_info->rtc_type == TODC_TYPE_DS17285) {
+               u_char mode;
+
+               mode = todc_read_val(TODC_TYPE_DS17285_CNTL_A);
+               /* Make sure countdown clear is not set */
+               mode &= ~0x40;
+               /* Enable oscillator, extended register set */
+               mode |= 0x30;
+               todc_write_val(TODC_TYPE_DS17285_CNTL_A, mode);
+
+       } else if (todc_info->rtc_type == TODC_TYPE_DS1501) {
+               u_char  month;
+
+               todc_info->enable_read = TODC_DS1501_CNTL_B_TE;
+               todc_info->enable_write = TODC_DS1501_CNTL_B_TE;
+
+               month = todc_read_val(todc_info->month);
+
+               if ((month & 0x80) == 0x80) {
+                       printk(KERN_INFO "TODC %s %s\n",
+                               "real-time-clock was stopped.",
+                               "Now starting...");
+                       month &= ~0x80;
+                       todc_write_val(todc_info->month, month);
+               }
+
+               cntl_b &= ~TODC_DS1501_CNTL_B_TE;
+               todc_write_val(todc_info->control_b, cntl_b);
+       } else { /* must be a m48txx type */
+               u_char  cntl_a;
+
+               todc_info->enable_read = TODC_MK48TXX_CNTL_A_R;
+               todc_info->enable_write = TODC_MK48TXX_CNTL_A_W;
+
+               cntl_a = todc_read_val(todc_info->control_a);
+
+               /* Check & clear STOP bit in control B register */
+               if (cntl_b & TODC_MK48TXX_DAY_CB) {
+                       printk(KERN_INFO "TODC %s %s\n",
+                               "real-time-clock was stopped.",
+                               "Now starting...");
+
+                       cntl_a |= todc_info->enable_write;
+                       cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */
+
+                       todc_write_val(todc_info->control_a, cntl_a);
+                       todc_write_val(todc_info->control_b, cntl_b);
+               }
+
+               /* Make sure READ & WRITE bits are cleared. */
+               cntl_a &= ~(todc_info->enable_write | todc_info->enable_read);
+               todc_write_val(todc_info->control_a, cntl_a);
+       }
+
+       return 0;
+}
+
+/*
+ * There is some ugly stuff in that there are assumptions that for a mc146818,
+ * the todc_info->control_a has the offset of the mc146818 Register B reg and
+ * that the register'ss 'SET' bit is the same as the m48txx's write enable
+ * bit in the control register of the m48txx (i.e., 0x80).
+ *
+ * It was done to make the code look simpler.
+ */
+void
+todc_get_rtc_time(struct rtc_time *tm)
+{
+       uint    year = 0, mon = 0, mday = 0, hour = 0, min = 0, sec = 0;
+       uint    limit, i;
+       u_char  save_control, uip = 0;
+       extern void GregorianDay(struct rtc_time *);
+
+       spin_lock(&rtc_lock);
+       save_control = todc_read_val(todc_info->control_a);
+
+       if (todc_info->rtc_type != TODC_TYPE_MC146818) {
+               limit = 1;
+
+               switch (todc_info->rtc_type) {
+               case TODC_TYPE_DS1553:
+               case TODC_TYPE_DS1557:
+               case TODC_TYPE_DS1743:
+               case TODC_TYPE_DS1746:  /* XXXX BAD HACK -> FIX */
+               case TODC_TYPE_DS1747:
+               case TODC_TYPE_DS17285:
+                       break;
+               default:
+                       todc_write_val(todc_info->control_a,
+                               (save_control | todc_info->enable_read));
+               }
+       } else
+               limit = 100000000;
+
+       for (i=0; i<limit; i++) {
+               if (todc_info->rtc_type == TODC_TYPE_MC146818)
+                       uip = todc_read_val(todc_info->RTC_FREQ_SELECT);
+
+               sec = todc_read_val(todc_info->seconds) & 0x7f;
+               min = todc_read_val(todc_info->minutes) & 0x7f;
+               hour = todc_read_val(todc_info->hours) & 0x3f;
+               mday = todc_read_val(todc_info->day_of_month) & 0x3f;
+               mon = todc_read_val(todc_info->month) & 0x1f;
+               year = todc_read_val(todc_info->year) & 0xff;
+
+               if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+                       uip |= todc_read_val(todc_info->RTC_FREQ_SELECT);
+                       if ((uip & RTC_UIP) == 0)
+                               break;
+               }
+       }
+
+       if (todc_info->rtc_type != TODC_TYPE_MC146818) {
+               switch (todc_info->rtc_type) {
+               case TODC_TYPE_DS1553:
+               case TODC_TYPE_DS1557:
+               case TODC_TYPE_DS1743:
+               case TODC_TYPE_DS1746:  /* XXXX BAD HACK -> FIX */
+               case TODC_TYPE_DS1747:
+               case TODC_TYPE_DS17285:
+                       break;
+               default:
+                       save_control &= ~(todc_info->enable_read);
+                       todc_write_val(todc_info->control_a, save_control);
+               }
+       }
+       spin_unlock(&rtc_lock);
+
+       if ((todc_info->rtc_type != TODC_TYPE_MC146818)
+                       || ((save_control & RTC_DM_BINARY) == 0)
+                       || RTC_ALWAYS_BCD) {
+               BCD_TO_BIN(sec);
+               BCD_TO_BIN(min);
+               BCD_TO_BIN(hour);
+               BCD_TO_BIN(mday);
+               BCD_TO_BIN(mon);
+               BCD_TO_BIN(year);
+       }
+
+       if ((year + 1900) < 1970) {
+               year += 100;
+       }
+
+       tm->tm_sec = sec;
+       tm->tm_min = min;
+       tm->tm_hour = hour;
+       tm->tm_mday = mday;
+       tm->tm_mon = mon;
+       tm->tm_year = year;
+
+       GregorianDay(tm);
+}
+
+int
+todc_set_rtc_time(struct rtc_time *tm)
+{
+       u_char save_control, save_freq_select = 0;
+
+       spin_lock(&rtc_lock);
+       save_control = todc_read_val(todc_info->control_a);
+
+       /* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */
+       todc_write_val(todc_info->control_a,
+               (save_control | todc_info->enable_write));
+       save_control &= ~(todc_info->enable_write); /* in case it was set */
+
+       if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+               save_freq_select = todc_read_val(todc_info->RTC_FREQ_SELECT);
+               todc_write_val(todc_info->RTC_FREQ_SELECT,
+                       save_freq_select | RTC_DIV_RESET2);
+       }
+
+       if ((todc_info->rtc_type != TODC_TYPE_MC146818)
+                       || ((save_control & RTC_DM_BINARY) == 0)
+                       || RTC_ALWAYS_BCD) {
+               BIN_TO_BCD(tm->tm_sec);
+               BIN_TO_BCD(tm->tm_min);
+               BIN_TO_BCD(tm->tm_hour);
+               BIN_TO_BCD(tm->tm_mon);
+               BIN_TO_BCD(tm->tm_mday);
+               BIN_TO_BCD(tm->tm_year);
+       }
+
+       todc_write_val(todc_info->seconds, tm->tm_sec);
+       todc_write_val(todc_info->minutes, tm->tm_min);
+       todc_write_val(todc_info->hours, tm->tm_hour);
+       todc_write_val(todc_info->month, tm->tm_mon);
+       todc_write_val(todc_info->day_of_month, tm->tm_mday);
+       todc_write_val(todc_info->year, tm->tm_year);
+
+       todc_write_val(todc_info->control_a, save_control);
+
+       if (todc_info->rtc_type == TODC_TYPE_MC146818)
+               todc_write_val(todc_info->RTC_FREQ_SELECT, save_freq_select);
+
+       spin_unlock(&rtc_lock);
+       return 0;
+}
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c
new file mode 100644 (file)
index 0000000..26a0cc8
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * tsi108/109 device setup code
+ *
+ * Maintained by Roy Zang < tie-fei.zang@freescale.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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/tsi108.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <mm/mmu_decl.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+static phys_addr_t tsi108_csr_base = -1;
+
+phys_addr_t get_csrbase(void)
+{
+       struct device_node *tsi;
+
+       if (tsi108_csr_base != -1)
+               return tsi108_csr_base;
+
+       tsi = of_find_node_by_type(NULL, "tsi-bridge");
+       if (tsi) {
+               unsigned int size;
+               void *prop = get_property(tsi, "reg", &size);
+               tsi108_csr_base = of_translate_address(tsi, prop);
+               of_node_put(tsi);
+       };
+       return tsi108_csr_base;
+}
+
+u32 get_vir_csrbase(void)
+{
+       return (u32) (ioremap(get_csrbase(), 0x10000));
+}
+
+EXPORT_SYMBOL(get_csrbase);
+EXPORT_SYMBOL(get_vir_csrbase);
+
+static int __init tsi108_eth_of_init(void)
+{
+       struct device_node *np;
+       unsigned int i;
+       struct platform_device *tsi_eth_dev;
+       struct resource res;
+       int ret;
+
+       for (np = NULL, i = 0;
+            (np = of_find_compatible_node(np, "network", "tsi-ethernet")) != NULL;
+            i++) {
+               struct resource r[2];
+               struct device_node *phy;
+               hw_info tsi_eth_data;
+               unsigned int *id;
+               unsigned int *phy_id;
+               void *mac_addr;
+               phandle *ph;
+
+               memset(r, 0, sizeof(r));
+               memset(&tsi_eth_data, 0, sizeof(tsi_eth_data));
+
+               ret = of_address_to_resource(np, 0, &r[0]);
+               DBG("%s: name:start->end = %s:0x%lx-> 0x%lx\n",
+                       __FUNCTION__,r[0].name, r[0].start, r[0].end);
+               if (ret)
+                       goto err;
+
+               r[1].name = "tx";
+               r[1].start = np->intrs[0].line;
+               r[1].end = np->intrs[0].line;
+               r[1].flags = IORESOURCE_IRQ;
+
+               tsi_eth_dev =
+                   platform_device_register_simple("tsi-ethernet", i, &r[0],
+                                                   np->n_intrs + 1);
+
+               if (IS_ERR(tsi_eth_dev)) {
+                       ret = PTR_ERR(tsi_eth_dev);
+                       goto err;
+               }
+
+               mac_addr = get_property(np, "address", NULL);
+               memcpy(tsi_eth_data.mac_addr, mac_addr, 6);
+
+               ph = (phandle *) get_property(np, "phy-handle", NULL);
+               phy = of_find_node_by_phandle(*ph);
+
+               if (phy == NULL) {
+                       ret = -ENODEV;
+                       goto unreg;
+               }
+
+               id = (u32 *) get_property(phy, "reg", NULL);
+               phy_id = (u32 *) get_property(phy, "phy-id", NULL);
+               ret = of_address_to_resource(phy, 0, &res);
+               if (ret) {
+                       of_node_put(phy);
+                       goto unreg;
+               }
+               tsi_eth_data.regs = r[0].start;
+               tsi_eth_data.phyregs = res.start;
+               tsi_eth_data.phy = *phy_id;
+               tsi_eth_data.irq_num = np->intrs[0].line;
+               of_node_put(phy);
+               ret =
+                   platform_device_add_data(tsi_eth_dev, &tsi_eth_data,
+                                            sizeof(hw_info));
+               if (ret)
+                       goto unreg;
+       }
+       return 0;
+unreg:
+       platform_device_unregister(tsi_eth_dev);
+err:
+       return ret;
+}
+
+arch_initcall(tsi108_eth_of_init);
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
new file mode 100644 (file)
index 0000000..3265d54
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * Common routines for Tundra Semiconductor TSI108 host bridge.
+ *
+ * 2004-2005 (c) Tundra Semiconductor Corp.
+ * Author: Alex Bounine (alexandreb@tundra.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/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/tsi108.h>
+#include <asm/tsi108_irq.h>
+#include <asm/prom.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define tsi_mk_config_addr(bus, devfunc, offset) \
+       ((((bus)<<16) | ((devfunc)<<8) | (offset & 0xfc)) + tsi108_pci_cfg_base)
+
+u32 tsi108_pci_cfg_base;
+u32 tsi108_csr_vir_base;
+
+extern u32 get_vir_csrbase(void);
+extern u32 tsi108_read_reg(u32 reg_offset);
+extern void tsi108_write_reg(u32 reg_offset, u32 val);
+
+int
+tsi108_direct_write_config(struct pci_bus *bus, unsigned int devfunc,
+                          int offset, int len, u32 val)
+{
+       volatile unsigned char *cfg_addr;
+
+       if (ppc_md.pci_exclude_device)
+               if (ppc_md.pci_exclude_device(bus->number, devfunc))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+
+       cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number,
+                                                       devfunc, offset) |
+                                                       (offset & 0x03));
+
+#ifdef DEBUG
+       printk("PCI CFG write : ");
+       printk("%d:0x%x:0x%x ", bus->number, devfunc, offset);
+       printk("%d ADDR=0x%08x ", len, (uint) cfg_addr);
+       printk("data = 0x%08x\n", val);
+#endif
+
+       switch (len) {
+       case 1:
+               out_8((u8 *) cfg_addr, val);
+               break;
+       case 2:
+               out_le16((u16 *) cfg_addr, val);
+               break;
+       default:
+               out_le32((u32 *) cfg_addr, val);
+               break;
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+void tsi108_clear_pci_error(u32 pci_cfg_base)
+{
+       u32 err_stat, err_addr, pci_stat;
+
+       /*
+        * Quietly clear PB and PCI error flags set as result
+        * of PCI/X configuration read requests.
+        */
+
+       /* Read PB Error Log Registers */
+
+       err_stat = tsi108_read_reg(TSI108_PB_OFFSET + TSI108_PB_ERRCS);
+       err_addr = tsi108_read_reg(TSI108_PB_OFFSET + TSI108_PB_AERR);
+
+       if (err_stat & TSI108_PB_ERRCS_ES) {
+               /* Clear error flag */
+               tsi108_write_reg(TSI108_PB_OFFSET + TSI108_PB_ERRCS,
+                                TSI108_PB_ERRCS_ES);
+
+               /* Clear read error reported in PB_ISR */
+               tsi108_write_reg(TSI108_PB_OFFSET + TSI108_PB_ISR,
+                                TSI108_PB_ISR_PBS_RD_ERR);
+
+               /* Clear PCI/X bus cfg errors if applicable */
+               if ((err_addr & 0xFF000000) == pci_cfg_base) {
+                       pci_stat =
+                           tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_CSR);
+                       tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_CSR,
+                                        pci_stat);
+               }
+       }
+
+       return;
+}
+
+#define __tsi108_read_pci_config(x, addr, op)          \
+       __asm__ __volatile__(                           \
+               "       "op" %0,0,%1\n"         \
+               "1:     eieio\n"                        \
+               "2:\n"                                  \
+               ".section .fixup,\"ax\"\n"              \
+               "3:     li %0,-1\n"                     \
+               "       b 2b\n"                         \
+               ".section __ex_table,\"a\"\n"           \
+               "       .align 2\n"                     \
+               "       .long 1b,3b\n"                  \
+               ".text"                                 \
+               : "=r"(x) : "r"(addr))
+
+int
+tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                         int len, u32 * val)
+{
+       volatile unsigned char *cfg_addr;
+       u32 temp;
+
+       if (ppc_md.pci_exclude_device)
+               if (ppc_md.pci_exclude_device(bus->number, devfn))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+
+       cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number,
+                                                       devfn,
+                                                       offset) | (offset &
+                                                                  0x03));
+
+       switch (len) {
+       case 1:
+               __tsi108_read_pci_config(temp, cfg_addr, "lbzx");
+               break;
+       case 2:
+               __tsi108_read_pci_config(temp, cfg_addr, "lhbrx");
+               break;
+       default:
+               __tsi108_read_pci_config(temp, cfg_addr, "lwbrx");
+               break;
+       }
+
+       *val = temp;
+
+#ifdef DEBUG
+       if ((0xFFFFFFFF != temp) && (0xFFFF != temp) && (0xFF != temp)) {
+               printk("PCI CFG read : ");
+               printk("%d:0x%x:0x%x ", bus->number, devfn, offset);
+               printk("%d ADDR=0x%08x ", len, (uint) cfg_addr);
+               printk("data = 0x%x\n", *val);
+       }
+#endif
+       return PCIBIOS_SUCCESSFUL;
+}
+
+void tsi108_clear_pci_cfg_error(void)
+{
+       tsi108_clear_pci_error(TSI108_PCI_CFG_BASE_PHYS);
+}
+
+static struct pci_ops tsi108_direct_pci_ops = {
+       tsi108_direct_read_config,
+       tsi108_direct_write_config
+};
+
+int __init tsi108_setup_pci(struct device_node *dev)
+{
+       int len;
+       struct pci_controller *hose;
+       struct resource rsrc;
+       int *bus_range;
+       int primary = 0, has_address = 0;
+
+       /* PCI Config mapping */
+       tsi108_pci_cfg_base = (u32)ioremap(TSI108_PCI_CFG_BASE_PHYS,
+                       TSI108_PCI_CFG_SIZE);
+       DBG("TSI_PCI: %s tsi108_pci_cfg_base=0x%x\n", __FUNCTION__,
+           tsi108_pci_cfg_base);
+
+       /* Fetch host bridge registers address */
+       has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+       /* Get bus range if any */
+       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 = pcibios_alloc_controller();
+
+       if (!hose) {
+               printk("PCI Host bridge init failed\n");
+               return -ENOMEM;
+       }
+       hose->arch_data = dev;
+       hose->set_cfg_type = 1;
+
+       hose->first_busno = bus_range ? bus_range[0] : 0;
+       hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+       (hose)->ops = &tsi108_direct_pci_ops;
+
+       printk(KERN_INFO "Found tsi108 PCI host bridge at 0x%08lx. "
+              "Firmware bus number: %d->%d\n",
+              rsrc.start, 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, primary);
+       return 0;
+}
+
+/*
+ * Low level utility functions
+ */
+
+static void tsi108_pci_int_mask(u_int irq)
+{
+       u_int irp_cfg;
+       int int_line = (irq - IRQ_PCI_INTAD_BASE);
+
+       irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
+       mb();
+       irp_cfg |= (1 << int_line);     /* INTx_DIR = output */
+       irp_cfg &= ~(3 << (8 + (int_line * 2)));        /* INTx_TYPE = unused */
+       tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL, irp_cfg);
+       mb();
+       irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
+}
+
+static void tsi108_pci_int_unmask(u_int irq)
+{
+       u_int irp_cfg;
+       int int_line = (irq - IRQ_PCI_INTAD_BASE);
+
+       irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
+       mb();
+       irp_cfg &= ~(1 << int_line);
+       irp_cfg |= (3 << (8 + (int_line * 2)));
+       tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL, irp_cfg);
+       mb();
+}
+
+static void init_pci_source(void)
+{
+       tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL,
+                       0x0000ff00);
+       tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE,
+                       TSI108_PCI_IRP_ENABLE_P_INT);
+       mb();
+}
+
+static inline int get_pci_source(void)
+{
+       u_int temp = 0;
+       int irq = -1;
+       int i;
+       u_int pci_irp_stat;
+       static int mask = 0;
+
+       /* Read PCI/X block interrupt status register */
+       pci_irp_stat = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_STAT);
+       mb();
+
+       if (pci_irp_stat & TSI108_PCI_IRP_STAT_P_INT) {
+               /* Process Interrupt from PCI bus INTA# - INTD# lines */
+               temp =
+                   tsi108_read_reg(TSI108_PCI_OFFSET +
+                                   TSI108_PCI_IRP_INTAD) & 0xf;
+               mb();
+               for (i = 0; i < 4; i++, mask++) {
+                       if (temp & (1 << mask % 4)) {
+                               irq = IRQ_PCI_INTA + mask % 4;
+                               mask++;
+                               break;
+                       }
+               }
+
+               /* Disable interrupts from PCI block */
+               temp = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE);
+               tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE,
+                               temp & ~TSI108_PCI_IRP_ENABLE_P_INT);
+               mb();
+               (void)tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE);
+               mb();
+       }
+#ifdef DEBUG
+       else {
+               printk("TSI108_PIC: error in TSI108_PCI_IRP_STAT\n");
+               pci_irp_stat =
+                   tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_STAT);
+               temp =
+                   tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_INTAD);
+               mb();
+               printk(">> stat=0x%08x intad=0x%08x ", pci_irp_stat, temp);
+               temp =
+                   tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
+               mb();
+               printk("cfg_ctl=0x%08x ", temp);
+               temp =
+                   tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE);
+               mb();
+               printk("irp_enable=0x%08x\n", temp);
+       }
+#endif /* end of DEBUG */
+
+       return irq;
+}
+
+
+/*
+ * Linux descriptor level callbacks
+ */
+
+static void tsi108_pci_irq_enable(u_int irq)
+{
+       tsi108_pci_int_unmask(irq);
+}
+
+static void tsi108_pci_irq_disable(u_int irq)
+{
+       tsi108_pci_int_mask(irq);
+}
+
+static void tsi108_pci_irq_ack(u_int irq)
+{
+       tsi108_pci_int_mask(irq);
+}
+
+static void tsi108_pci_irq_end(u_int irq)
+{
+       tsi108_pci_int_unmask(irq);
+
+       /* Enable interrupts from PCI block */
+       tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE,
+                        tsi108_read_reg(TSI108_PCI_OFFSET +
+                                        TSI108_PCI_IRP_ENABLE) |
+                        TSI108_PCI_IRP_ENABLE_P_INT);
+       mb();
+}
+
+/*
+ * Interrupt controller descriptor for cascaded PCI interrupt controller.
+ */
+
+struct hw_interrupt_type tsi108_pci_irq = {
+       .typename = "tsi108_PCI_int",
+       .enable = tsi108_pci_irq_enable,
+       .disable = tsi108_pci_irq_disable,
+       .ack = tsi108_pci_irq_ack,
+       .end = tsi108_pci_irq_end,
+};
+
+/*
+ * Exported functions
+ */
+
+/*
+ * The Tsi108 PCI interrupts initialization routine.
+ *
+ * The INTA# - INTD# interrupts on the PCI bus are reported by the PCI block
+ * to the MPIC using single interrupt source (IRQ_TSI108_PCI). Therefore the
+ * PCI block has to be treated as a cascaded interrupt controller connected
+ * to the MPIC.
+ */
+
+void __init tsi108_pci_int_init(void)
+{
+       u_int i;
+
+       DBG("Tsi108_pci_int_init: initializing PCI interrupts\n");
+
+       for (i = 0; i < NUM_PCI_IRQS; i++) {
+               irq_desc[i + IRQ_PCI_INTAD_BASE].handler = &tsi108_pci_irq;
+               irq_desc[i + IRQ_PCI_INTAD_BASE].status |= IRQ_LEVEL;
+       }
+
+       init_pci_source();
+}
+
+int tsi108_irq_cascade(struct pt_regs *regs, void *unused)
+{
+       return get_pci_source();
+}
index 98b25fa0049a2cbf561bee7400046f23b7976c1a..1e113d0f59b8e3cbfa760f1aec1734c4b530c313 100644 (file)
@@ -1758,7 +1758,7 @@ int __init siccuart_init(void)
     siccnormal_driver->subtype = SERIAL_TYPE_NORMAL;
     siccnormal_driver->init_termios = tty_std_termios;
     siccnormal_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-    siccnormal_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+    siccnormal_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
     tty_set_operations(siccnormal_driver, &sicc_ops);
 
     if (tty_register_driver(siccnormal_driver))
index 12b84ca51327f570d8becc0696c0cd405f2edadc..9b3ace26280cb85301fd2954492f6dcb47530750 100644 (file)
@@ -187,7 +187,7 @@ cpm_interrupt_init(void)
          * interrupt vectors
          */
         for ( i = CPM_IRQ_OFFSET ; i < CPM_IRQ_OFFSET + NR_CPM_INTS ; i++ )
-                irq_desc[i].handler = &cpm_pic;
+                irq_desc[i].chip = &cpm_pic;
 
        /* Set our interrupt handler with the core CPU. */
        if (setup_irq(CPM_INTERRUPT, &cpm_interrupt_irqaction))
index b55de4f42aec1a8b4db42d2379c43cbf7f89b4c5..a04cdf01596b1ac6ddec4b4c42c253f0c4094059 100644 (file)
@@ -219,10 +219,10 @@ config KEXEC
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
-         but it is indepedent of the system firmware.   And like a reboot
+         but it is independent of the system firmware.   And like a reboot
          you can start any kernel with it, not just Linux.
 
-         The name comes from the similiarity to the exec system call.
+         The name comes from the similarity to the exec system call.
 
          It is an ongoing process to be certain the hardware in a machine
          is properly shutdown, so do not be surprised if this code does not
index d20accf9650dcbacc4ec88806c074d150cd10dca..242bb052be679f66bca5345fdeda0f226ef90046 100644 (file)
@@ -95,8 +95,10 @@ pcibios_fixup_resources(struct pci_dev *dev)
                if (!res->flags)
                        continue;
                if (res->end == 0xffffffff) {
-                       DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n",
-                           pci_name(dev), i, res->start, res->end);
+                       DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n",
+                               pci_name(dev), i,
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end);
                        res->end -= res->start;
                        res->start = 0;
                        res->flags |= IORESOURCE_UNSET;
@@ -169,18 +171,18 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
  * but we want to try to avoid allocating at 0x2900-0x2bff
  * which might have be mirrored at 0x0100-0x03ff..
  */
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size,
-                      unsigned long align)
+void pcibios_align_resource(void *data, struct resource *res,
+                               resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
 
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (size > 0x100) {
                        printk(KERN_ERR "PCI: I/O Region %s/%d too large"
-                              " (%ld bytes)\n", pci_name(dev),
-                              dev->resource - res, size);
+                              " (%lld bytes)\n", pci_name(dev),
+                              dev->resource - res, (unsigned long long)size);
                }
 
                if (start & 0x300) {
@@ -251,8 +253,9 @@ pcibios_allocate_bus_resources(struct list_head *bus_list)
                                }
                        }
 
-                       DBG("PCI: bridge rsrc %lx..%lx (%lx), parent %p\n",
-                           res->start, res->end, res->flags, pr);
+                       DBG("PCI: bridge rsrc %llx..%llx (%lx), parent %p\n",
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end, res->flags, pr);
                        if (pr) {
                                if (request_resource(pr, res) == 0)
                                        continue;
@@ -302,8 +305,9 @@ reparent_resources(struct resource *parent, struct resource *res)
        *pp = NULL;
        for (p = res->child; p != NULL; p = p->sibling) {
                p->parent = res;
-               DBG(KERN_INFO "PCI: reparented %s [%lx..%lx] under %s\n",
-                   p->name, p->start, p->end, res->name);
+               DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n",
+                       p->name, (unsigned long long)p->start,
+                       (unsigned long long)p->end, res->name);
        }
        return 0;
 }
@@ -358,13 +362,15 @@ pci_relocate_bridge_resource(struct pci_bus *bus, int i)
                try = conflict->start - 1;
        }
        if (request_resource(pr, res)) {
-               DBG(KERN_ERR "PCI: huh? couldn't move to %lx..%lx\n",
-                   res->start, res->end);
+               DBG(KERN_ERR "PCI: huh? couldn't move to %llx..%llx\n",
+                       (unsigned long long)res->start,
+                       (unsigned long long)res->end);
                return -1;              /* "can't happen" */
        }
        update_bridge_base(bus, i);
-       printk(KERN_INFO "PCI: bridge %d resource %d moved to %lx..%lx\n",
-              bus->number, i, res->start, res->end);
+       printk(KERN_INFO "PCI: bridge %d resource %d moved to %llx..%llx\n",
+               bus->number, i, (unsigned long long)res->start,
+               (unsigned long long)res->end);
        return 0;
 }
 
@@ -475,15 +481,17 @@ static inline void alloc_resource(struct pci_dev *dev, int idx)
 {
        struct resource *pr, *r = &dev->resource[idx];
 
-       DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx)\n",
-           pci_name(dev), idx, r->start, r->end, r->flags);
+       DBG("PCI:%s: Resource %d: %016llx-%016llx (f=%lx)\n",
+           pci_name(dev), idx, (unsigned long long)r->start,
+           (unsigned long long)r->end, r->flags);
        pr = pci_find_parent_resource(dev, r);
        if (!pr || request_resource(pr, r) < 0) {
                printk(KERN_ERR "PCI: Cannot allocate resource region %d"
                       " of device %s\n", idx, pci_name(dev));
                if (pr)
-                       DBG("PCI:  parent is %p: %08lx-%08lx (f=%lx)\n",
-                           pr, pr->start, pr->end, pr->flags);
+                       DBG("PCI:  parent is %p: %016llx-%016llx (f=%lx)\n",
+                               pr, (unsigned long long)pr->start,
+                               (unsigned long long)pr->end, pr->flags);
                /* We'll assign a new address later */
                r->flags |= IORESOURCE_UNSET;
                r->end -= r->start;
@@ -952,8 +960,8 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
        else
                prot |= _PAGE_GUARDED;
 
-       printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
-              prot);
+       printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev),
+               (unsigned long long)rp->start, prot);
 
        return __pgprot(prot);
 }
@@ -1122,7 +1130,7 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
 
 void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
-                         u64 *start, u64 *end)
+                         resource_size_t *start, resource_size_t *end)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
        unsigned long offset = 0;
index 1f79e84ab464dd8a416eaab3d104e8aff11ea6d5..4b4607d89bfa6e1c105a01d85c0a674748c5fa8f 100644 (file)
@@ -475,7 +475,7 @@ int __init ppc_init(void)
 
        /* register CPU devices */
        for_each_possible_cpu(i)
-               register_cpu(&cpu_devices[i], i, NULL);
+               register_cpu(&cpu_devices[i], i);
 
        /* call platform init */
        if (ppc_md.init != NULL) {
index fe0cdc04d4366b0c9460486e25d8b00eb4a58a76..5c4118a459f3eb1b6822b5817ee16248f9c9da48 100644 (file)
@@ -734,9 +734,9 @@ void apus_init_IRQ(void)
        for ( i = 0 ; i < AMI_IRQS; i++ ) {
                irq_desc[i].status = IRQ_LEVEL;
                if (i < IRQ_AMIGA_AUTO) {
-                       irq_desc[i].handler = &amiga_irqctrl;
+                       irq_desc[i].chip = &amiga_irqctrl;
                } else {
-                       irq_desc[i].handler = &amiga_sys_irqctrl;
+                       irq_desc[i].chip = &amiga_sys_irqctrl;
                        action = &amiga_sys_irqaction[i-IRQ_AMIGA_AUTO];
                        if (action->name)
                                setup_irq(i, action);
index 866807b4ad0b32ffc32b92c281180b64a4356e9b..41006d2b4b3823a3438f2d79e43caf67b77ee5ab 100644 (file)
@@ -172,7 +172,7 @@ void __init sbc82xx_init_IRQ(void)
        
        /* Set up the interrupt handlers for the i8259 IRQs */
        for (i = NR_SIU_INTS; i < NR_SIU_INTS + 8; i++) {
-                irq_desc[i].handler = &sbc82xx_i8259_ic;
+                irq_desc[i].chip = &sbc82xx_i8259_ic;
                irq_desc[i].status |= IRQ_LEVEL;
        }
 
index 5add0a919ef6182695f88fee3d149bbdd985e7b5..172aa215fdb0d1ac059c725187f9afdc4f5aaaf7 100644 (file)
@@ -140,12 +140,12 @@ cpc700_init_IRQ(void)
                                                        /* IRQ 0 is highest */
 
        for (i = 0; i < 17; i++) {
-               irq_desc[i].handler = &cpc700_pic;
+               irq_desc[i].chip = &cpc700_pic;
                cpc700_pic_init_irq(i);
        }
 
        for (i = 20; i < 32; i++) {
-               irq_desc[i].handler = &cpc700_pic;
+               irq_desc[i].chip = &cpc700_pic;
                cpc700_pic_init_irq(i);
        }
 
index 29d95d415ceb7f70accd8c8381f9666f748be467..c0fee0beb81503722a64053122be7fe90d017b4f 100644 (file)
@@ -171,7 +171,7 @@ void cpm2_init_IRQ(void)
        /* Enable chaining to OpenPIC, and make everything level
         */
        for (i = 0; i < NR_CPM_INTS; i++) {
-               irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic;
+               irq_desc[i+CPM_IRQ_OFFSET].chip = &cpm2_pic;
                irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
        }
 }
index dc3bd9ecbbf6956c88079e1fc5a40e27c3c774f9..91096b38ae70297b77fcd8820e3e51a5d6ecf030 100644 (file)
@@ -98,7 +98,7 @@ gt64260_init_irq(void)
 
        /* use the gt64260 for all (possible) interrupt sources */
        for (i = gt64260_irq_base; i < (gt64260_irq_base + 96); i++)
-               irq_desc[i].handler = &gt64260_pic;
+               irq_desc[i].chip = &gt64260_pic;
 
        if (ppc_md.progress)
                ppc_md.progress("gt64260_init_irq: exit", 0x0);
index 1941a8c7ca9a3dbd851b619c6e55ea7b39bc5dcf..63fa5b313396b42fba12d24cc801b34921b49f96 100644 (file)
@@ -159,7 +159,7 @@ pq2pci_init_irq(void)
        immap->im_memctl.memc_or8 = 0xffff8010;
 #endif
        for (irq = NR_CPM_INTS; irq < NR_CPM_INTS + 4; irq++)
-               irq_desc[irq].handler = &pq2pci_ic;
+               irq_desc[irq].chip = &pq2pci_ic;
 
        /* make PCI IRQ level sensitive */
        immap->im_intctl.ic_siexr &=
index dae9af78bde1ba4674f889be162f87312bbe0733..0c4c0de7c59f0b10990969215b0bca76d37a8c55 100644 (file)
@@ -347,13 +347,13 @@ m8xx_init_IRQ(void)
        int i;
 
        for (i = SIU_IRQ_OFFSET ; i < SIU_IRQ_OFFSET + NR_SIU_INTS ; i++)
-               irq_desc[i].handler = &ppc8xx_pic;
+               irq_desc[i].chip = &ppc8xx_pic;
 
        cpm_interrupt_init();
 
 #if defined(CONFIG_PCI)
        for (i = I8259_IRQ_OFFSET ; i < I8259_IRQ_OFFSET + NR_8259_INTS ; i++)
-               irq_desc[i].handler = &i8259_pic;
+               irq_desc[i].chip = &i8259_pic;
 
        i8259_pic_irq_offset = I8259_IRQ_OFFSET;
        i8259_init(0);
index c4406f9dc6a3d0d8c2174524533b914a4313f1af..6425b5cee7db2bc7c638c5c5faa41b07467af98b 100644 (file)
@@ -204,9 +204,9 @@ mpc52xx_init_irq(void)
        out_be32(&intr->main_pri1, 0);
        out_be32(&intr->main_pri2, 0);
 
-       /* Initialize irq_desc[i].handler's with mpc52xx_ic. */
+       /* Initialize irq_desc[i].chip's with mpc52xx_ic. */
        for (i = 0; i < NR_IRQS; i++) {
-               irq_desc[i].handler = &mpc52xx_ic;
+               irq_desc[i].chip = &mpc52xx_ic;
                irq_desc[i].status = IRQ_LEVEL;
        }
 
index 5a19697060f0290ba124adb2fca72001ad82e0a3..a4244d46838197d0b6b20126ba7a454f2b7659f8 100644 (file)
@@ -119,7 +119,7 @@ mv64360_init_irq(void)
        /* All interrupts are level interrupts */
        for (i = mv64360_irq_base; i < (mv64360_irq_base + 96); i++) {
                irq_desc[i].status |= IRQ_LEVEL;
-               irq_desc[i].handler = &mv64360_pic;
+               irq_desc[i].chip = &mv64360_pic;
        }
 
        if (ppc_md.progress)
index 70456c8f998c7be7c992cad3ec8c8a61c2959fa4..767a0bc9581765fb21c70920a0fc93e7b3697735 100644 (file)
@@ -373,7 +373,7 @@ void __init openpic_init(int offset)
                                OPENPIC_VEC_IPI+i+offset);
                /* IPIs are per-CPU */
                irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
-               irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
+               irq_desc[OPENPIC_VEC_IPI+i+offset].chip = &open_pic_ipi;
        }
 #endif
 
@@ -408,7 +408,7 @@ void __init openpic_init(int offset)
 
        /* Init descriptors */
        for (i = offset; i < NumSources + offset; i++)
-               irq_desc[i].handler = &open_pic;
+               irq_desc[i].chip = &open_pic;
 
        /* Initialize the spurious interrupt */
        if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
@@ -615,8 +615,8 @@ void __devinit do_openpic_setup_cpu(void)
        /* let the openpic 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.
+        * we should make sure we also change the default values of
+        * irq_desc[].affinity in irq.c.
         */
        for (i = 0; i < NumSources; i++)
                openpic_mapirq(i, msk, CPU_MASK_ALL);
index bcbe40de26fe511cf42aba2faa98ff449a7f00d9..b8154efff6ede2c7a14224a920542b4650488dac 100644 (file)
@@ -290,7 +290,7 @@ void __init openpic2_init(int offset)
 
        /* Init descriptors */
        for (i = offset; i < NumSources + offset; i++)
-               irq_desc[i].handler = &open_pic2;
+               irq_desc[i].chip = &open_pic2;
 
        /* Initialize the spurious interrupt */
        if (ppc_md.progress) ppc_md.progress("openpic2: spurious",0x3bd);
index c46043c47225b72b737d79dcaac46cb2a4ced2bf..1584c8b1229f76bac6627a939c4d3efd9b206d4d 100644 (file)
@@ -121,5 +121,5 @@ ppc4xx_pic_init(void)
        ppc_md.get_irq = ppc403_pic_get_irq;
 
        for (i = 0; i < NR_IRQS; i++)
-               irq_desc[i].handler = &ppc403_aic;
+               irq_desc[i].chip = &ppc403_aic;
 }
index fd9af0fc0e9f43ddce46abdba519b73e6c6c1810..e669c1335d47e93bf46a603e2e9ce1dd098420a3 100644 (file)
@@ -276,7 +276,7 @@ void __init ppc4xx_pic_init(void)
 
        /* Attach low-level handlers */
        for (i = 0; i < (NR_UICS << 5); ++i) {
-               irq_desc[i].handler = &__uic[i >> 5].decl;
+               irq_desc[i].chip = &__uic[i >> 5].decl;
                if (is_level_sensitive(i))
                        irq_desc[i].status |= IRQ_LEVEL;
        }
index e672b600f315499a50b84a5ee5750e86f0e8e5c7..39a93dc6375b82a074aad29b9774865e27f001a5 100644 (file)
@@ -143,7 +143,7 @@ ppc4xx_pic_init(void)
        ppc_md.get_irq = xilinx_pic_get_irq;
 
        for (i = 0; i < NR_IRQS; ++i) {
-               irq_desc[i].handler = &xilinx_intc;
+               irq_desc[i].chip = &xilinx_intc;
 
                if (XPAR_INTC_0_KIND_OF_INTR & (0x00000001 << i))
                        irq_desc[i].status &= ~IRQ_LEVEL;
index e806a8922bbbe83e180e806fcbdf28efef5af700..71d65eb30650463345a6d02ca7e680b3b3f27240 100644 (file)
@@ -3,9 +3,9 @@
  *
  * Definitions and interface for Linux - z/VM Monitor Stream.
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 //#define APPLDATA_DEBUG                       /* Debug messages on/off */
 #define CTL_APPLDATA_NET_SUM   2125
 #define CTL_APPLDATA_PROC      2126
 
+#ifndef CONFIG_64BIT
+
+#define APPLDATA_START_INTERVAL_REC 0x00       /* Function codes for */
+#define APPLDATA_STOP_REC          0x01        /* DIAG 0xDC      */
+#define APPLDATA_GEN_EVENT_RECORD   0x02
+#define APPLDATA_START_CONFIG_REC   0x03
+
+#else
+
+#define APPLDATA_START_INTERVAL_REC 0x80
+#define APPLDATA_STOP_REC          0x81
+#define APPLDATA_GEN_EVENT_RECORD   0x82
+#define APPLDATA_START_CONFIG_REC   0x83
+
+#endif /* CONFIG_64BIT */
+
 #define P_INFO(x...)   printk(KERN_INFO MY_PRINT_NAME " info: " x)
 #define P_ERROR(x...)  printk(KERN_ERR MY_PRINT_NAME " error: " x)
 #define P_WARNING(x...)        printk(KERN_WARNING MY_PRINT_NAME " status: " x)
@@ -53,7 +69,11 @@ struct appldata_ops {
        void *data;                             /* record data */
        unsigned int size;                      /* size of record */
        struct module *owner;                   /* THIS_MODULE */
+       char mod_lvl[2];                        /* modification level, EBCDIC */
 };
 
 extern int appldata_register_ops(struct appldata_ops *ops);
 extern void appldata_unregister_ops(struct appldata_ops *ops);
+extern int appldata_diag(char record_nr, u16 function, unsigned long buffer,
+                        u16 length, char *mod_lvl);
+
index 9a22434a580c52f1245bedd5d0a1a6a7d81d7866..61bc44626c043ec2bb41c0e61399b2e1127680ae 100644 (file)
@@ -5,9 +5,9 @@
  * Exports appldata_register_ops() and appldata_unregister_ops() for the
  * data gathering modules.
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
 
 #define TOD_MICRO      0x01000                 /* nr. of TOD clock units
                                                   for 1 microsecond */
-#ifndef CONFIG_64BIT
-
-#define APPLDATA_START_INTERVAL_REC 0x00       /* Function codes for */
-#define APPLDATA_STOP_REC          0x01        /* DIAG 0xDC      */
-#define APPLDATA_GEN_EVENT_RECORD   0x02
-#define APPLDATA_START_CONFIG_REC   0x03
-
-#else
-
-#define APPLDATA_START_INTERVAL_REC 0x80
-#define APPLDATA_STOP_REC          0x81
-#define APPLDATA_GEN_EVENT_RECORD   0x82
-#define APPLDATA_START_CONFIG_REC   0x83
-
-#endif /* CONFIG_64BIT */
-
 
 /*
  * Parameter list for DIAGNOSE X'DC'
@@ -195,8 +179,8 @@ static void appldata_work_fn(void *data)
  *
  * prepare parameter list, issue DIAG 0xDC
  */
-static int appldata_diag(char record_nr, u16 function, unsigned long buffer,
-                       u16 length)
+int appldata_diag(char record_nr, u16 function, unsigned long buffer,
+                       u16 length, char *mod_lvl)
 {
        unsigned long ry;
        struct appldata_product_id {
@@ -214,7 +198,7 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer,
                .record_nr  = record_nr,
                .version_nr = {0xF2, 0xF6},             /* "26" */
                .release_nr = {0xF0, 0xF1},             /* "01" */
-               .mod_lvl    = {0xF0, 0xF0},             /* "00" */
+               .mod_lvl    = {mod_lvl[0], mod_lvl[1]},
        };
        struct appldata_parameter_list appldata_parameter_list = {
                                .diag = 0xDC,
@@ -467,24 +451,25 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                        module_put(ops->owner);
                        return -ENODEV;
                }
-               ops->active = 1;
                ops->callback(ops->data);       // init record
                rc = appldata_diag(ops->record_nr,
                                        APPLDATA_START_INTERVAL_REC,
-                                       (unsigned long) ops->data, ops->size);
+                                       (unsigned long) ops->data, ops->size,
+                                       ops->mod_lvl);
                if (rc != 0) {
                        P_ERROR("START DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
                        module_put(ops->owner);
-                       ops->active = 0;
                } else {
                        P_INFO("Monitoring %s data enabled, "
                                "DIAG 0xDC started.\n", ops->name);
+                       ops->active = 1;
                }
        } else if ((buf[0] == '0') && (ops->active == 1)) {
                ops->active = 0;
                rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
-                               (unsigned long) ops->data, ops->size);
+                               (unsigned long) ops->data, ops->size,
+                               ops->mod_lvl);
                if (rc != 0) {
                        P_ERROR("STOP DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
@@ -633,7 +618,7 @@ appldata_offline_cpu(int cpu)
        spin_unlock(&appldata_timer_lock);
 }
 
-static int
+static int __cpuinit
 appldata_cpu_notify(struct notifier_block *self,
                    unsigned long action, void *hcpu)
 {
@@ -652,7 +637,7 @@ appldata_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block appldata_nb = {
+static struct notifier_block __devinitdata appldata_nb = {
        .notifier_call = appldata_cpu_notify,
 };
 
@@ -710,7 +695,8 @@ static void __exit appldata_exit(void)
        list_for_each(lh, &appldata_ops_list) {
                ops = list_entry(lh, struct appldata_ops, list);
                rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
-                               (unsigned long) ops->data, ops->size);
+                               (unsigned long) ops->data, ops->size,
+                               ops->mod_lvl);
                if (rc != 0) {
                        P_ERROR("STOP DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
@@ -739,6 +725,7 @@ MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure");
 
 EXPORT_SYMBOL_GPL(appldata_register_ops);
 EXPORT_SYMBOL_GPL(appldata_unregister_ops);
+EXPORT_SYMBOL_GPL(appldata_diag);
 
 #ifdef MODULE
 /*
@@ -779,7 +766,6 @@ unsigned long nr_iowait(void)
 #endif /* MODULE */
 EXPORT_SYMBOL_GPL(si_swapinfo);
 EXPORT_SYMBOL_GPL(nr_threads);
-EXPORT_SYMBOL_GPL(avenrun);
 EXPORT_SYMBOL_GPL(get_full_page_state);
 EXPORT_SYMBOL_GPL(nr_running);
 EXPORT_SYMBOL_GPL(nr_iowait);
index f0e2fbed3d4cf86a8000ec212e435546098507fc..7915a197d96d227bb2175ada9125be89399fafa5 100644 (file)
@@ -4,9 +4,9 @@
  * Data gathering module for Linux-VM Monitor Stream, Stage 1.
  * Collects data related to memory management.
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -152,6 +152,7 @@ static struct appldata_ops ops = {
        .callback  = &appldata_get_mem_data,
        .data      = &appldata_mem_data,
        .owner     = THIS_MODULE,
+       .mod_lvl   = {0xF0, 0xF0},              /* EBCDIC "00" */
 };
 
 
index 2a4c7432db4ac2960cde34ee6033671fe171cfc5..39b7bdecbf0563f38046245af32d0258c2054c05 100644 (file)
@@ -5,9 +5,9 @@
  * Collects accumulated network statistics (Packets received/transmitted,
  * dropped, errors, ...).
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -152,6 +152,7 @@ static struct appldata_ops ops = {
        .callback  = &appldata_get_net_sum_data,
        .data      = &appldata_net_sum_data,
        .owner     = THIS_MODULE,
+       .mod_lvl   = {0xF0, 0xF0},              /* EBCDIC "00" */
 };
 
 
index 99ddd3bf2fbaac6bb2e5ef49fbd43e7c16bac0f2..f2b44a2f1deca958c9f1840d47407b149a730041 100644 (file)
@@ -4,9 +4,9 @@
  * Data gathering module for Linux-VM Monitor Stream, Stage 1.
  * Collects misc. OS related data (CPU utilization, running processes).
  *
- * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -44,11 +44,14 @@ struct appldata_os_per_cpu {
        u32 per_cpu_system;     /* ... spent in kernel mode         */
        u32 per_cpu_idle;       /* ... spent in idle mode           */
 
-// New in 2.6 -->
+       /* New in 2.6 */
        u32 per_cpu_irq;        /* ... spent in interrupts          */
        u32 per_cpu_softirq;    /* ... spent in softirqs            */
        u32 per_cpu_iowait;     /* ... spent while waiting for I/O  */
-// <-- New in 2.6
+
+       /* New in modification level 01 */
+       u32 per_cpu_steal;      /* ... stolen by hypervisor         */
+       u32 cpu_id;             /* number of this CPU               */
 } __attribute__((packed));
 
 struct appldata_os_data {
@@ -68,10 +71,9 @@ struct appldata_os_data {
        u32 avenrun[3];         /* average nr. of running processes during */
                                /* the last 1, 5 and 15 minutes */
 
-// New in 2.6 -->
+       /* New in 2.6 */
        u32 nr_iowait;          /* number of blocked threads
                                   (waiting for I/O)               */
-// <-- New in 2.6
 
        /* per cpu data */
        struct appldata_os_per_cpu os_cpu[0];
@@ -79,6 +81,14 @@ struct appldata_os_data {
 
 static struct appldata_os_data *appldata_os_data;
 
+static struct appldata_ops ops = {
+       .ctl_nr    = CTL_APPLDATA_OS,
+       .name      = "os",
+       .record_nr = APPLDATA_RECORD_OS_ID,
+       .owner     = THIS_MODULE,
+       .mod_lvl   = {0xF0, 0xF1},              /* EBCDIC "01" */
+};
+
 
 static inline void appldata_print_debug(struct appldata_os_data *os_data)
 {
@@ -100,15 +110,17 @@ static inline void appldata_print_debug(struct appldata_os_data *os_data)
        P_DEBUG("nr_cpus = %u\n", os_data->nr_cpus);
        for (i = 0; i < os_data->nr_cpus; i++) {
                P_DEBUG("cpu%u : user = %u, nice = %u, system = %u, "
-                       "idle = %u, irq = %u, softirq = %u, iowait = %u\n",
-                               i,
+                       "idle = %u, irq = %u, softirq = %u, iowait = %u, "
+                       "steal = %u\n",
+                               os_data->os_cpu[i].cpu_id,
                                os_data->os_cpu[i].per_cpu_user,
                                os_data->os_cpu[i].per_cpu_nice,
                                os_data->os_cpu[i].per_cpu_system,
                                os_data->os_cpu[i].per_cpu_idle,
                                os_data->os_cpu[i].per_cpu_irq,
                                os_data->os_cpu[i].per_cpu_softirq,
-                               os_data->os_cpu[i].per_cpu_iowait);
+                               os_data->os_cpu[i].per_cpu_iowait,
+                               os_data->os_cpu[i].per_cpu_steal);
        }
 
        P_DEBUG("sync_count_1 = %u\n", os_data->sync_count_1);
@@ -123,14 +135,13 @@ static inline void appldata_print_debug(struct appldata_os_data *os_data)
  */
 static void appldata_get_os_data(void *data)
 {
-       int i, j;
+       int i, j, rc;
        struct appldata_os_data *os_data;
+       unsigned int new_size;
 
        os_data = data;
        os_data->sync_count_1++;
 
-       os_data->nr_cpus = num_online_cpus();
-
        os_data->nr_threads = nr_threads;
        os_data->nr_running = nr_running();
        os_data->nr_iowait  = nr_iowait();
@@ -154,9 +165,44 @@ static void appldata_get_os_data(void *data)
                        cputime_to_jiffies(kstat_cpu(i).cpustat.softirq);
                os_data->os_cpu[j].per_cpu_iowait =
                        cputime_to_jiffies(kstat_cpu(i).cpustat.iowait);
+               os_data->os_cpu[j].per_cpu_steal =
+                       cputime_to_jiffies(kstat_cpu(i).cpustat.steal);
+               os_data->os_cpu[j].cpu_id = i;
                j++;
        }
 
+       os_data->nr_cpus = j;
+
+       new_size = sizeof(struct appldata_os_data) +
+                  (os_data->nr_cpus * sizeof(struct appldata_os_per_cpu));
+       if (ops.size != new_size) {
+               if (ops.active) {
+                       rc = appldata_diag(APPLDATA_RECORD_OS_ID,
+                                          APPLDATA_START_INTERVAL_REC,
+                                          (unsigned long) ops.data, new_size,
+                                          ops.mod_lvl);
+                       if (rc != 0) {
+                               P_ERROR("os: START NEW DIAG 0xDC failed, "
+                                       "return code: %d, new size = %i\n", rc,
+                                       new_size);
+                               P_INFO("os: stopping old record now\n");
+                       } else
+                               P_INFO("os: new record size = %i\n", new_size);
+
+                       rc = appldata_diag(APPLDATA_RECORD_OS_ID,
+                                          APPLDATA_STOP_REC,
+                                          (unsigned long) ops.data, ops.size,
+                                          ops.mod_lvl);
+                       if (rc != 0)
+                               P_ERROR("os: STOP OLD DIAG 0xDC failed, "
+                                       "return code: %d, old size = %i\n", rc,
+                                       ops.size);
+                       else
+                               P_INFO("os: old record size = %i stopped\n",
+                                       ops.size);
+               }
+               ops.size = new_size;
+       }
        os_data->timestamp = get_clock();
        os_data->sync_count_2++;
 #ifdef APPLDATA_DEBUG
@@ -165,15 +211,6 @@ static void appldata_get_os_data(void *data)
 }
 
 
-static struct appldata_ops ops = {
-       .ctl_nr    = CTL_APPLDATA_OS,
-       .name      = "os",
-       .record_nr = APPLDATA_RECORD_OS_ID,
-       .callback  = &appldata_get_os_data,
-       .owner     = THIS_MODULE,
-};
-
-
 /*
  * appldata_os_init()
  *
@@ -181,26 +218,25 @@ static struct appldata_ops ops = {
  */
 static int __init appldata_os_init(void)
 {
-       int rc, size;
+       int rc, max_size;
 
-       size = sizeof(struct appldata_os_data) +
-               (NR_CPUS * sizeof(struct appldata_os_per_cpu));
-       if (size > APPLDATA_MAX_REC_SIZE) {
-               P_ERROR("Size of record = %i, bigger than maximum (%i)!\n",
-                       size, APPLDATA_MAX_REC_SIZE);
+       max_size = sizeof(struct appldata_os_data) +
+                  (NR_CPUS * sizeof(struct appldata_os_per_cpu));
+       if (max_size > APPLDATA_MAX_REC_SIZE) {
+               P_ERROR("Max. size of OS record = %i, bigger than maximum "
+                       "record size (%i)\n", max_size, APPLDATA_MAX_REC_SIZE);
                rc = -ENOMEM;
                goto out;
        }
-       P_DEBUG("sizeof(os) = %i, sizeof(os_cpu) = %lu\n", size,
+       P_DEBUG("max. sizeof(os) = %i, sizeof(os_cpu) = %lu\n", max_size,
                sizeof(struct appldata_os_per_cpu));
 
-       appldata_os_data = kmalloc(size, GFP_DMA);
+       appldata_os_data = kzalloc(max_size, GFP_DMA);
        if (appldata_os_data == NULL) {
                P_ERROR("No memory for %s!\n", ops.name);
                rc = -ENOMEM;
                goto out;
        }
-       memset(appldata_os_data, 0, size);
 
        appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu);
        appldata_os_data->cpu_offset   = offsetof(struct appldata_os_data,
@@ -208,7 +244,7 @@ static int __init appldata_os_init(void)
        P_DEBUG("cpu offset = %u\n", appldata_os_data->cpu_offset);
 
        ops.data = appldata_os_data;
-       ops.size = size;
+       ops.callback  = &appldata_get_os_data;
        rc = appldata_register_ops(&ops);
        if (rc != 0) {
                P_ERROR("Error registering ops, rc = %i\n", rc);
index 1f451c2cb071896f7032e990ac78256769a74c58..12a6311e9838901ed2ca106a9e34f778bd33be27 100644 (file)
@@ -177,11 +177,6 @@ struct elf_prpsinfo32
 
 #include <linux/highuid.h>
 
-#undef NEW_TO_OLD_UID
-#undef NEW_TO_OLD_GID
-#define NEW_TO_OLD_UID(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
-#define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid) 
-
 #define elf_addr_t     u32
 /*
 #define init_elf_binfmt init_elf32_binfmt
index b2448487854cfbd5a36aae778be1eebec9184211..aa8b52c2140f1e672bed5c4be2715d10140e01f4 100644 (file)
@@ -93,13 +93,22 @@ STACK_SIZE  = 1 << STACK_SHIFT
        l       %r13,__LC_SVC_NEW_PSW+4 # load &system_call to %r13
        .endm
 
-       .macro  SAVE_ALL psworg,savearea,sync
+       .macro  SAVE_ALL_SYNC psworg,savearea
        la      %r12,\psworg
-       .if     \sync
        tm      \psworg+1,0x01          # test problem state bit
        bz      BASED(2f)               # skip stack setup save
        l       %r15,__LC_KERNEL_STACK  # problem state -> load ksp
-       .else
+#ifdef CONFIG_CHECK_STACK
+       b       BASED(3f)
+2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
+       bz      BASED(stack_overflow)
+3:
+#endif
+2:
+       .endm
+
+       .macro  SAVE_ALL_ASYNC psworg,savearea
+       la      %r12,\psworg
        tm      \psworg+1,0x01          # test problem state bit
        bnz     BASED(1f)               # from user -> load async stack
        clc     \psworg+4(4),BASED(.Lcritical_end)
@@ -115,7 +124,6 @@ STACK_SIZE  = 1 << STACK_SHIFT
        sra     %r14,STACK_SHIFT
        be      BASED(2f)
 1:     l       %r15,__LC_ASYNC_STACK
-       .endif
 #ifdef CONFIG_CHECK_STACK
        b       BASED(3f)
 2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
@@ -196,7 +204,7 @@ system_call:
        STORE_TIMER __LC_SYNC_ENTER_TIMER
 sysc_saveall:
        SAVE_ALL_BASE __LC_SAVE_AREA
-        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        lh      %r7,0x8a          # get svc number from lowcore
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -425,7 +433,7 @@ pgm_check_handler:
        SAVE_ALL_BASE __LC_SAVE_AREA
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         bnz     BASED(pgm_per)           # got per exception -> special case
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -464,7 +472,7 @@ pgm_per:
 # Normal per exception
 #
 pgm_per_std:
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -490,7 +498,7 @@ pgm_no_vtime2:
 # it was a single stepped SVC that is causing all the trouble
 #
 pgm_svcper:
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -519,7 +527,7 @@ io_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+16
-        SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
+       SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
        CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -631,7 +639,7 @@ ext_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+16
-        SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
+       SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
        CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -657,21 +665,31 @@ __critical_end:
         .globl mcck_int_handler
 mcck_int_handler:
        spt     __LC_CPU_TIMER_SAVE_AREA        # revalidate cpu timer
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA
        lm      %r0,%r15,__LC_GPREGS_SAVE_AREA  # revalidate gprs
        SAVE_ALL_BASE __LC_SAVE_AREA+32
        la      %r12,__LC_MCK_OLD_PSW
        tm      __LC_MCCK_CODE,0x80     # system damage?
        bo      BASED(mcck_int_main)    # yes -> rest of mcck code invalid
-       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
-       bo      BASED(0f)
-       spt     __LC_LAST_UPDATE_TIMER  # revalidate cpu timer
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_SYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_EXIT_TIMER(8),__LC_LAST_UPDATE_TIMER
+       mvc     __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA
+       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
+       bo      BASED(1f)
+       la      %r14,__LC_SYNC_ENTER_TIMER
+       clc     0(8,%r14),__LC_ASYNC_ENTER_TIMER
+       bl      BASED(0f)
+       la      %r14,__LC_ASYNC_ENTER_TIMER
+0:     clc     0(8,%r14),__LC_EXIT_TIMER
+       bl      BASED(0f)
+       la      %r14,__LC_EXIT_TIMER
+0:     clc     0(8,%r14),__LC_LAST_UPDATE_TIMER
+       bl      BASED(0f)
+       la      %r14,__LC_LAST_UPDATE_TIMER
+0:     spt     0(%r14)
+       mvc     __LC_ASYNC_ENTER_TIMER(8),0(%r14)
+1:
 #endif
-0:     tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
        bno     BASED(mcck_int_main)    # no -> skip cleanup critical
        tm      __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
        bnz     BASED(mcck_int_main)    # from user -> load async stack
@@ -691,7 +709,7 @@ mcck_int_main:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      __LC_MCCK_CODE+2,0x08   # mwp of old psw valid?
        bno     BASED(mcck_no_vtime)    # no -> skip cleanup critical
-       tm      __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        bz      BASED(mcck_no_vtime)
        UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@@ -715,6 +733,20 @@ mcck_no_vtime:
        l       %r1,BASED(.Ls390_handle_mcck)
        basr    %r14,%r1                # call machine check handler
 mcck_return:
+       mvc     __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW
+       ni      __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+52
+       tm      __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
+       bno     BASED(0f)
+       lm      %r0,%r15,SP_R0(%r15)    # load gprs 0-15
+       stpt    __LC_EXIT_TIMER
+       lpsw    __LC_RETURN_MCCK_PSW    # back to caller
+0:
+#endif
+       lm      %r0,%r15,SP_R0(%r15)    # load gprs 0-15
+       lpsw    __LC_RETURN_MCCK_PSW    # back to caller
+
         RESTORE_ALL __LC_RETURN_MCCK_PSW,0
 
 #ifdef CONFIG_SMP
@@ -781,6 +813,8 @@ cleanup_table_sysc_leave:
        .long   sysc_leave + 0x80000000, sysc_work_loop + 0x80000000
 cleanup_table_sysc_work_loop:
        .long   sysc_work_loop + 0x80000000, sysc_reschedule + 0x80000000
+cleanup_table_io_return:
+       .long   io_return + 0x80000000, io_leave + 0x80000000
 cleanup_table_io_leave:
        .long   io_leave + 0x80000000, io_done + 0x80000000
 cleanup_table_io_work_loop:
@@ -806,6 +840,11 @@ cleanup_critical:
        bl      BASED(0f)
        clc     4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
        bl      BASED(cleanup_sysc_return)
+0:
+       clc     4(4,%r12),BASED(cleanup_table_io_return)
+       bl      BASED(0f)
+       clc     4(4,%r12),BASED(cleanup_table_io_return+4)
+       bl      BASED(cleanup_io_return)
 0:
        clc     4(4,%r12),BASED(cleanup_table_io_leave)
        bl      BASED(0f)
@@ -839,7 +878,7 @@ cleanup_system_call:
        mvc     __LC_SAVE_AREA(16),0(%r12)
 0:     st      %r13,4(%r12)
        st      %r12,__LC_SAVE_AREA+48  # argh
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        l       %r12,__LC_SAVE_AREA+48  # argh
        st      %r15,12(%r12)
@@ -980,7 +1019,6 @@ cleanup_io_leave_insn:
                .long  cleanup_critical
 
 #define SYSCALL(esa,esame,emu) .long esa
-       .globl  sys_call_table
 sys_call_table:
 #include "syscalls.S"
 #undef SYSCALL
index 2ac095bc0e250373588ba658916d0bdc700577fc..f3222a1b286174b97ed2141f0007a98b8a5af780 100644 (file)
@@ -87,13 +87,22 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
        larl    %r13,system_call
        .endm
 
-        .macro  SAVE_ALL psworg,savearea,sync
+       .macro  SAVE_ALL_SYNC psworg,savearea
        la      %r12,\psworg
-       .if     \sync
        tm      \psworg+1,0x01          # test problem state bit
        jz      2f                      # skip stack setup save
        lg      %r15,__LC_KERNEL_STACK  # problem state -> load ksp
-       .else
+#ifdef CONFIG_CHECK_STACK
+       j       3f
+2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
+       jz      stack_overflow
+3:
+#endif
+2:
+       .endm
+
+       .macro  SAVE_ALL_ASYNC psworg,savearea
+       la      %r12,\psworg
        tm      \psworg+1,0x01          # test problem state bit
        jnz     1f                      # from user -> load kernel stack
        clc     \psworg+8(8),BASED(.Lcritical_end)
@@ -108,7 +117,6 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
        srag    %r14,%r14,STACK_SHIFT
        jz      2f
 1:     lg      %r15,__LC_ASYNC_STACK   # load async stack
-       .endif
 #ifdef CONFIG_CHECK_STACK
        j       3f
 2:     tml     %r15,STACK_SIZE - CONFIG_STACK_GUARD
@@ -187,7 +195,7 @@ system_call:
        STORE_TIMER __LC_SYNC_ENTER_TIMER
 sysc_saveall:
        SAVE_ALL_BASE __LC_SAVE_AREA
-        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
         CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        llgh    %r7,__LC_SVC_INT_CODE # get svc number from lowcore
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -446,7 +454,7 @@ pgm_check_handler:
        SAVE_ALL_BASE __LC_SAVE_AREA
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         jnz     pgm_per                  # got per exception -> special case
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -485,7 +493,7 @@ pgm_per:
 # Normal per exception
 #
 pgm_per_std:
-       SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -511,7 +519,7 @@ pgm_no_vtime2:
 # it was a single stepped SVC that is causing all the trouble
 #
 pgm_svcper:
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -539,7 +547,7 @@ io_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+32
-        SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0
+       SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
        CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -647,7 +655,7 @@ ext_int_handler:
        STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+32
-        SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0
+       SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
        CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
@@ -672,21 +680,32 @@ __critical_end:
 mcck_int_handler:
        la      %r1,4095                # revalidate r1
        spt     __LC_CPU_TIMER_SAVE_AREA-4095(%r1)      # revalidate cpu timer
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r1)
        lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
        SAVE_ALL_BASE __LC_SAVE_AREA+64
        la      %r12,__LC_MCK_OLD_PSW
        tm      __LC_MCCK_CODE,0x80     # system damage?
        jo      mcck_int_main           # yes -> rest of mcck code invalid
-       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
-       jo      0f
-       spt     __LC_LAST_UPDATE_TIMER
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_SYNC_ENTER_TIMER(8),__LC_LAST_UPDATE_TIMER
-       mvc     __LC_EXIT_TIMER(8),__LC_LAST_UPDATE_TIMER
+       la      %r14,4095
+       mvc     __LC_SAVE_AREA+104(8),__LC_ASYNC_ENTER_TIMER
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14)
+       tm      __LC_MCCK_CODE+5,0x02   # stored cpu timer value valid?
+       jo      1f
+       la      %r14,__LC_SYNC_ENTER_TIMER
+       clc     0(8,%r14),__LC_ASYNC_ENTER_TIMER
+       jl      0f
+       la      %r14,__LC_ASYNC_ENTER_TIMER
+0:     clc     0(8,%r14),__LC_EXIT_TIMER
+       jl      0f
+       la      %r14,__LC_EXIT_TIMER
+0:     clc     0(8,%r14),__LC_LAST_UPDATE_TIMER
+       jl      0f
+       la      %r14,__LC_LAST_UPDATE_TIMER
+0:     spt     0(%r14)
+       mvc     __LC_ASYNC_ENTER_TIMER(8),0(%r14)
+1:
 #endif
-0:     tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
+       tm      __LC_MCCK_CODE+2,0x09   # mwp + ia of old psw valid?
        jno     mcck_int_main           # no -> skip cleanup critical
        tm      __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
        jnz     mcck_int_main           # from user -> load kernel stack
@@ -705,7 +724,7 @@ mcck_int_main:
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
        tm      __LC_MCCK_CODE+2,0x08   # mwp of old psw valid?
        jno     mcck_no_vtime           # no -> no timer update
-       tm      __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
        jz      mcck_no_vtime
        UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@@ -727,7 +746,17 @@ mcck_no_vtime:
        jno     mcck_return
        brasl   %r14,s390_handle_mcck
 mcck_return:
-        RESTORE_ALL __LC_RETURN_MCCK_PSW,0
+       mvc     __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW
+       ni      __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
+       lmg     %r0,%r15,SP_R0(%r15)    # load gprs 0-15
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       mvc     __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+104
+       tm      __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
+       jno     0f
+       stpt    __LC_EXIT_TIMER
+0:
+#endif
+       lpswe   __LC_RETURN_MCCK_PSW    # back to caller
 
 #ifdef CONFIG_SMP
 /*
@@ -789,6 +818,8 @@ cleanup_table_sysc_leave:
        .quad   sysc_leave, sysc_work_loop
 cleanup_table_sysc_work_loop:
        .quad   sysc_work_loop, sysc_reschedule
+cleanup_table_io_return:
+       .quad   io_return, io_leave
 cleanup_table_io_leave:
        .quad   io_leave, io_done
 cleanup_table_io_work_loop:
@@ -814,6 +845,11 @@ cleanup_critical:
        jl      0f
        clc     8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
        jl      cleanup_sysc_return
+0:
+       clc     8(8,%r12),BASED(cleanup_table_io_return)
+       jl      0f
+       clc     8(8,%r12),BASED(cleanup_table_io_return+8)
+       jl      cleanup_io_return
 0:
        clc     8(8,%r12),BASED(cleanup_table_io_leave)
        jl      0f
@@ -847,7 +883,7 @@ cleanup_system_call:
        mvc     __LC_SAVE_AREA(32),0(%r12)
 0:     stg     %r13,8(%r12)
        stg     %r12,__LC_SAVE_AREA+96  # argh
-       SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+       SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
        lg      %r12,__LC_SAVE_AREA+96  # argh
        stg     %r15,24(%r12)
@@ -957,7 +993,6 @@ cleanup_io_leave_insn:
                .quad  __critical_end
 
 #define SYSCALL(esa,esame,emu) .long esame
-       .globl  sys_call_table
 sys_call_table:
 #include "syscalls.S"
 #undef SYSCALL
@@ -965,7 +1000,6 @@ sys_call_table:
 #ifdef CONFIG_COMPAT
 
 #define SYSCALL(esa,esame,emu) .long emu
-       .globl  sys_call_table_emu
 sys_call_table_emu:
 #include "syscalls.S"
 #undef SYSCALL
index ea88d066bf04138a19bfa31fb7351b8737b2e81d..538c82da49b1b2d614f8aaa1e57b2d864fac2975 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/s390/kernel/head.S
  *
- * (C) Copyright IBM Corp. 1999, 2005
+ * Copyright (C) IBM Corp. 1999,2006
  *
  *    Author(s): Hartmut Penner <hp@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -482,24 +482,23 @@ start:
 
 .macro GET_IPL_DEVICE
 .Lget_ipl_device:
-       basr  %r12,0
-.LGID: l     %r1,0xb8                  # get sid
+       l     %r1,0xb8                  # get sid
        sll   %r1,15                    # test if subchannel is enabled
        srl   %r1,31
        ltr   %r1,%r1
-       bz    0(%r14)                   # subchannel disabled
+       bz    2f-.LPG1(%r13)            # subchannel disabled
        l     %r1,0xb8
-       la    %r5,.Lipl_schib-.LGID(%r12)
+       la    %r5,.Lipl_schib-.LPG1(%r13)
        stsch 0(%r5)                    # get schib of subchannel
-       bnz   0(%r14)                   # schib not available
+       bnz   2f-.LPG1(%r13)            # schib not available
        tm    5(%r5),0x01               # devno valid?
-       bno   0(%r14)
-       la    %r6,ipl_parameter_flags-.LGID(%r12)
+       bno   2f-.LPG1(%r13)
+       la    %r6,ipl_parameter_flags-.LPG1(%r13)
        oi    3(%r6),0x01               # set flag
-       la    %r2,ipl_devno-.LGID(%r12)
+       la    %r2,ipl_devno-.LPG1(%r13)
        mvc   0(2,%r2),6(%r5)           # store devno
        tm    4(%r5),0x80               # qdio capable device?
-       bno   0(%r14)
+       bno   2f-.LPG1(%r13)
        oi    3(%r6),0x02               # set flag
 
        # copy ipl parameters
@@ -523,7 +522,7 @@ start:
        ar    %r2,%r1
        sr    %r0,%r4
        jne   1b
-       b     0(%r14)
+       b     2f-.LPG1(%r13)
 
        .align 4
 .Lipl_schib:
@@ -537,6 +536,7 @@ ipl_parameter_flags:
        .globl ipl_devno
 ipl_devno:
        .word 0
+2:
 .endm
 
 #ifdef CONFIG_64BIT
index 2d3b089bfb83d37acbc8427889034573ed2d1213..d00de17b3778ef9fde54a971de2175922ab5b03d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/s390/kernel/head31.S
  *
- * (C) Copyright IBM Corp. 2005
+ * Copyright (C) IBM Corp. 2005,2006
  *
  *   Author(s):        Hartmut Penner <hp@de.ibm.com>
  *             Martin Schwidefsky <schwidefsky@de.ibm.com>
 # or linload or SALIPL
 #
        .org    0x10000
-startup:basr   %r13,0                   # get base
-.LPG1: l       %r1, .Lget_ipl_device_addr-.LPG1(%r13)
-       basr    %r14, %r1
+startup:basr   %r13,0                  # get base
+.LPG0: l       %r13,0f-.LPG0(%r13)
+       b       0(%r13)
+0:     .long   startup_continue
+
+#
+# params at 10400 (setup.h)
+#
+       .org    PARMAREA
+       .long   0,0                     # IPL_DEVICE
+       .long   0,RAMDISK_ORIGIN        # INITRD_START
+       .long   0,RAMDISK_SIZE          # INITRD_SIZE
+
+       .org    COMMAND_LINE
+       .byte   "root=/dev/ram0 ro"
+       .byte   0
+
+       .org    0x11000
+
+startup_continue:
+       basr    %r13,0                  # get base
+.LPG1: GET_IPL_DEVICE
        lctl    %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-       la      %r12,_pstart-.LPG1(%r13) # pointer to parameter area
-                                        # move IPL device to lowcore
+       l       %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
+                                       # move IPL device to lowcore
        mvc     __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
 
 #
@@ -51,8 +70,8 @@ startup:basr  %r13,0                   # get base
        a       %r1,__LC_EXT_NEW_PSW+4  # set handler
        st      %r1,__LC_EXT_NEW_PSW+4
 
-       la      %r4,_pstart-.LPG1(%r13) # %r4 is our index for sccb stuff
-       la      %r1, .Lsccb-PARMAREA(%r4)       # our sccb
+       l       %r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff
+       lr      %r1,%r4                 # our sccb
        .insn   rre,0xb2200000,%r2,%r1  # service call
        ipm     %r1
        srl     %r1,28                  # get cc code
@@ -63,7 +82,7 @@ startup:basr  %r13,0                   # get base
        be      .Lservicecall-.LPG1(%r13)
        lpsw    .Lwaitsclp-.LPG1(%r13)
 .Lsclph:
-       lh      %r1,.Lsccbr-PARMAREA(%r4)
+       lh      %r1,.Lsccbr-.Lsccb(%r4)
        chi     %r1,0x10                # 0x0010 is the sucess code
        je      .Lprocsccb              # let's process the sccb
        chi     %r1,0x1f0
@@ -74,7 +93,7 @@ startup:basr  %r13,0                   # get base
        b       .Lservicecall-.LPG1(%r13)
 .Lprocsccb:
        lhi     %r1,0
-       icm     %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
+       icm     %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
        jnz     .Lscnd
        lhi     %r1,0x800               # otherwise report 2GB
 .Lscnd:
@@ -84,10 +103,10 @@ startup:basr       %r13,0                   # get base
        lr      %r1,%r3
 .Lno2gb:
        xr      %r3,%r3                 # same logic
-       ic      %r3,.Lscpa1-PARMAREA(%r4)
+       ic      %r3,.Lscpa1-.Lsccb(%r4)
        chi     %r3,0x00
        jne     .Lcompmem
-       l       %r3,.Lscpa2-PARMAREA(%r13)
+       l       %r3,.Lscpa2-.Lsccb(%r4)
 .Lcompmem:
        mr      %r2,%r1                 # mem in MB on 128-bit
        l       %r1,.Lonemb-.LPG1(%r13)
@@ -95,8 +114,6 @@ startup:basr %r13,0                   # get base
        b       .Lfchunk-.LPG1(%r13)
 
        .align 4
-.Lget_ipl_device_addr:
-       .long   .Lget_ipl_device
 .Lpmask:
        .byte   0
 .align 8
@@ -242,6 +259,8 @@ startup:basr        %r13,0                   # get base
        .long   0                       # cr13: home space segment table
        .long   0xc0000000              # cr14: machine check handling off
        .long   0                       # cr15: linkage stack operations
+.Lduct:        .long   0,0,0,0,0,0,0,0
+       .long   0,0,0,0,0,0,0,0
 .Lpcmem:.long  0x00080000,0x80000000 + .Lchkmem
 .Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long  0x00080000,0x80000000 + .Lchkcsp
@@ -252,25 +271,9 @@ startup:basr       %r13,0                   # get base
 .Lmflags:.long machine_flags
 .Lbss_bgn:  .long __bss_start
 .Lbss_end:  .long _end
-
-       .org    PARMAREA-64
-.Lduct:        .long   0,0,0,0,0,0,0,0
-       .long   0,0,0,0,0,0,0,0
-
-#
-# params at 10400 (setup.h)
-#
-       .org    PARMAREA
-       .global _pstart
-_pstart:
-       .long   0,0                     # IPL_DEVICE
-       .long   0,RAMDISK_ORIGIN        # INITRD_START
-       .long   0,RAMDISK_SIZE          # INITRD_SIZE
-
-       .org    COMMAND_LINE
-       .byte   "root=/dev/ram0 ro"
-       .byte   0
-       .org    0x11000
+.Lparmaddr: .long PARMAREA
+.Lsccbaddr: .long .Lsccb
+       .align  4096
 .Lsccb:
        .hword  0x1000                  # length, one page
        .byte   0x00,0x00,0x00
@@ -287,18 +290,14 @@ _pstart:
 .Lscpincr2:
        .quad   0x00
        .fill   3984,1,0
-       .org    0x12000
-       .global _pend
-_pend:
-
-       GET_IPL_DEVICE
+       .align  4096
 
 #ifdef CONFIG_SHARED_KERNEL
        .org    0x100000
 #endif
 
 #
-# startup-code, running in virtual mode
+# startup-code, running in absolute addressing mode
 #
        .globl  _stext
 _stext:        basr    %r13,0                  # get base
index f08c06f45d5ceea01fcb70ab3051037af13fcf70..47744fcca930d92f3e2dad3184a64be84009d3c8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/s390/kernel/head64.S
  *
- * (C) Copyright IBM Corp. 1999,2005
+ * Copyright (C) IBM Corp. 1999,2006
  *
  *   Author(s):        Hartmut Penner <hp@de.ibm.com>
  *             Martin Schwidefsky <schwidefsky@de.ibm.com>
 # this is called either by the ipl loader or directly by PSW restart
 # or linload or SALIPL
 #
-        .org  0x10000
-startup:basr  %r13,0                     # get base
+       .org  0x10000
+startup:basr  %r13,0                    # get base
+.LPG0: l     %r13,0f-.LPG0(%r13)
+       b     0(%r13)
+0:     .long startup_continue
+
+#
+# params at 10400 (setup.h)
+#
+       .org   PARMAREA
+       .quad  0                        # IPL_DEVICE
+       .quad  RAMDISK_ORIGIN           # INITRD_START
+       .quad  RAMDISK_SIZE             # INITRD_SIZE
+
+       .org   COMMAND_LINE
+       .byte  "root=/dev/ram0 ro"
+       .byte  0
+
+       .org   0x11000
+
+startup_continue:
+       basr  %r13,0                     # get base
 .LPG1:  sll   %r13,1                     # remove high order bit
         srl   %r13,1
-       l     %r1,.Lget_ipl_device_addr-.LPG1(%r13)
-       basr  %r14,%r1
+       GET_IPL_DEVICE
         lhi   %r1,1                      # mode 1 = esame
         slr   %r0,%r0                    # set cpuid to zero
         sigp  %r1,%r0,0x12               # switch to esame mode
        sam64                            # switch to 64 bit mode
        lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-       larl  %r12,_pstart               # pointer to parameter area
+       lg    %r12,.Lparmaddr-.LPG1(%r13)# pointer to parameter area
                                         # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
 
@@ -55,8 +74,8 @@ startup:basr  %r13,0                     # get base
        larl  %r1,.Lsclph
        stg   %r1,__LC_EXT_NEW_PSW+8    # set handler
 
-       larl  %r4,_pstart               # %r4 is our index for sccb stuff
-       la    %r1,.Lsccb-PARMAREA(%r4)  # our sccb
+       larl  %r4,.Lsccb                # %r4 is our index for sccb stuff
+       lgr   %r1,%r4                   # our sccb
        .insn rre,0xb2200000,%r2,%r1    # service call
        ipm   %r1
        srl   %r1,28                    # get cc code
@@ -67,7 +86,7 @@ startup:basr  %r13,0                     # get base
        be    .Lservicecall-.LPG1(%r13)
        lpswe .Lwaitsclp-.LPG1(%r13)
 .Lsclph:
-       lh    %r1,.Lsccbr-PARMAREA(%r4)
+       lh    %r1,.Lsccbr-.Lsccb(%r4)
        chi   %r1,0x10                  # 0x0010 is the sucess code
        je    .Lprocsccb                # let's process the sccb
        chi   %r1,0x1f0
@@ -78,15 +97,15 @@ startup:basr  %r13,0                     # get base
        b     .Lservicecall-.LPG1(%r13)
 .Lprocsccb:
        lghi  %r1,0
-       icm   %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
+       icm   %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
        jnz   .Lscnd
-       lg    %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one
+       lg    %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one
 .Lscnd:
        xr    %r3,%r3                   # same logic
-       ic    %r3,.Lscpa1-PARMAREA(%r4)
+       ic    %r3,.Lscpa1-.Lsccb(%r4)
        chi   %r3,0x00
        jne   .Lcompmem
-       l     %r3,.Lscpa2-PARMAREA(%r13)
+       l     %r3,.Lscpa2-.Lsccb(%r4)
 .Lcompmem:
        mlgr  %r2,%r1                   # mem in MB on 128-bit
        l     %r1,.Lonemb-.LPG1(%r13)
@@ -94,8 +113,6 @@ startup:basr  %r13,0                     # get base
        b     .Lfchunk-.LPG1(%r13)
 
        .align 4
-.Lget_ipl_device_addr:
-       .long .Lget_ipl_device
 .Lpmask:
        .byte 0
        .align 8
@@ -242,29 +259,16 @@ startup:basr  %r13,0                     # get base
         .quad  0                        # cr13: home space segment table
         .quad  0xc0000000               # cr14: machine check handling off
         .quad  0                        # cr15: linkage stack operations
+.Lduct: .long 0,0,0,0,0,0,0,0
+       .long 0,0,0,0,0,0,0,0
 .Lpcmsk:.quad  0x0000000180000000
 .L4malign:.quad 0xffffffffffc00000
 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
 .Lnop: .long  0x07000700
+.Lparmaddr:
+       .quad   PARMAREA
 
-       .org PARMAREA-64
-.Lduct:        .long 0,0,0,0,0,0,0,0
-       .long 0,0,0,0,0,0,0,0
-
-#
-# params at 10400 (setup.h)
-#
-       .org   PARMAREA
-       .global _pstart
-_pstart:
-       .quad  0                        # IPL_DEVICE
-        .quad  RAMDISK_ORIGIN           # INITRD_START
-        .quad  RAMDISK_SIZE             # INITRD_SIZE
-
-        .org   COMMAND_LINE
-       .byte  "root=/dev/ram0 ro"
-        .byte  0
-       .org   0x11000
+       .align 4096
 .Lsccb:
        .hword 0x1000                   # length, one page
        .byte 0x00,0x00,0x00
@@ -281,18 +285,14 @@ _pstart:
 .Lscpincr2:
        .quad 0x00
        .fill 3984,1,0
-       .org 0x12000
-       .global _pend
-_pend: 
-
-       GET_IPL_DEVICE
+       .align 4096
 
 #ifdef CONFIG_SHARED_KERNEL
        .org   0x100000
 #endif
        
 #
-# startup-code, running in virtual mode
+# startup-code, running in absolute addressing mode
 #
         .globl _stext
 _stext:        basr  %r13,0                    # get base
@@ -326,4 +326,3 @@ _stext:     basr  %r13,0                    # get base
             .align 8
 .Ldw:       .quad  0x0002000180000000,0x0000000000000000
 .Laregs:    .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
index 4176c77670c41f222f22311376fc633e48f901d1..0886e739d12269a121b3a0cdf85f02e4b3c0c7fe 100644 (file)
@@ -46,8 +46,6 @@ EXPORT_SYMBOL(__down_interruptible);
  */
 extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs);
 EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(overflowuid);
-EXPORT_SYMBOL(overflowgid);
 EXPORT_SYMBOL(empty_zero_page);
 
 /*
index b282034452a4707357dadd5b75d9be0f3bd83206..2b2551e3510b196c30fe5834b2a18a9d151e52a5 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/seq_file.h>
 #include <linux/kernel_stat.h>
 #include <linux/device.h>
+#include <linux/notifier.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -115,6 +116,7 @@ void __devinit cpu_init (void)
  */
 char vmhalt_cmd[128] = "";
 char vmpoff_cmd[128] = "";
+char vmpanic_cmd[128] = "";
 
 static inline void strncpy_skip_quote(char *dst, char *src, int n)
 {
@@ -146,6 +148,38 @@ static int __init vmpoff_setup(char *str)
 
 __setup("vmpoff=", vmpoff_setup);
 
+static int vmpanic_notify(struct notifier_block *self, unsigned long event,
+                         void *data)
+{
+       if (MACHINE_IS_VM && strlen(vmpanic_cmd) > 0)
+               cpcmd(vmpanic_cmd, NULL, 0, NULL);
+
+       return NOTIFY_OK;
+}
+
+#define PANIC_PRI_VMPANIC      0
+
+static struct notifier_block vmpanic_nb = {
+       .notifier_call = vmpanic_notify,
+       .priority = PANIC_PRI_VMPANIC
+};
+
+static int __init vmpanic_setup(char *str)
+{
+       static int register_done __initdata = 0;
+
+       strncpy_skip_quote(vmpanic_cmd, str, 127);
+       vmpanic_cmd[127] = 0;
+       if (!register_done) {
+               register_done = 1;
+               atomic_notifier_chain_register(&panic_notifier_list,
+                                              &vmpanic_nb);
+       }
+       return 1;
+}
+
+__setup("vmpanic=", vmpanic_setup);
+
 /*
  * condev= and conmode= setup parameter.
  */
@@ -289,19 +323,34 @@ void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
 
 void machine_restart(char *command)
 {
-       console_unblank();
+       if (!in_interrupt() || oops_in_progress)
+               /*
+                * Only unblank the console if we are called in enabled
+                * context or a bust_spinlocks cleared the way for us.
+                */
+               console_unblank();
        _machine_restart(command);
 }
 
 void machine_halt(void)
 {
-       console_unblank();
+       if (!in_interrupt() || oops_in_progress)
+               /*
+                * Only unblank the console if we are called in enabled
+                * context or a bust_spinlocks cleared the way for us.
+                */
+               console_unblank();
        _machine_halt();
 }
 
 void machine_power_off(void)
 {
-       console_unblank();
+       if (!in_interrupt() || oops_in_progress)
+               /*
+                * Only unblank the console if we are called in enabled
+                * context or a bust_spinlocks cleared the way for us.
+                */
+               console_unblank();
        _machine_power_off();
 }
 
index 343120c9223d798d6cad38703153df30f83e683b..8e03219eea76051f23d5f97edf5f61cab622ba38 100644 (file)
@@ -869,7 +869,7 @@ static int __init topology_init(void)
        int ret;
 
        for_each_possible_cpu(cpu) {
-               ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL);
+               ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu);
                if (ret)
                        printk(KERN_WARNING "topology_init: register_cpu %d "
                               "failed (%d)\n", cpu, ret);
index a46793beeddda592d70797ed79fc4c462477f1d6..b7630436f693cda60aa7976b8c3a9b43212ab327 100644 (file)
@@ -150,13 +150,11 @@ void show_stack(struct task_struct *task, unsigned long *sp)
        unsigned long *stack;
        int i;
 
-       // debugging aid: "show_stack(NULL);" prints the
-       // back trace for this cpu.
-
        if (!sp)
-               sp = task ? (unsigned long *) task->thread.ksp : __r15;
+               stack = task ? (unsigned long *) task->thread.ksp : __r15;
+       else
+               stack = sp;
 
-       stack = sp;
        for (i = 0; i < kstack_depth_to_print; i++) {
                if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
                        break;
index 2bcecf42257343e0b2af310bf0b43b2b16fc3e93..1a0db1d4c952fe31e91729e3489e985aee32d31d 100644 (file)
@@ -465,10 +465,10 @@ config KEXEC
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
-         but it is indepedent of the system firmware.  And like a reboot
+         but it is independent of the system firmware.  And like a reboot
          you can start any kernel with it, not just Linux.
 
-         The name comes from the similiarity to the exec system call.
+         The name comes from the similarity to the exec system call.
 
          It is an ongoing process to be certain the hardware in a machine
          is properly shutdown, so do not be surprised if this code does not
index c0973f8d57bae3c6060a9f4e67ddf9a11adfef21..357fab1bac2ba518eebfc968260b2cd259ec8798 100644 (file)
@@ -102,6 +102,6 @@ static void end_maskreg_irq(unsigned int irq)
 void make_maskreg_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &maskreg_irq_type;
+       irq_desc[irq].chip = &maskreg_irq_type;
        disable_maskreg_irq(irq);
 }
index 6ddbcc77244da4d81653baa2c6bb2a6bb838debd..1d32425782c00cec5fb8ee72875202d2cd667268 100644 (file)
@@ -253,7 +253,7 @@ static void make_bigsur_l1isr(unsigned int irq) {
         /* sanity check first */
         if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
                 /* save the handler in the main description table */
-                irq_desc[irq].handler = &bigsur_l1irq_type;
+                irq_desc[irq].chip = &bigsur_l1irq_type;
                 irq_desc[irq].status = IRQ_DISABLED;
                 irq_desc[irq].action = 0;
                 irq_desc[irq].depth = 1;
@@ -270,7 +270,7 @@ static void make_bigsur_l2isr(unsigned int irq) {
         /* sanity check first */
         if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
                 /* save the handler in the main description table */
-                irq_desc[irq].handler = &bigsur_l2irq_type;
+                irq_desc[irq].chip = &bigsur_l2irq_type;
                 irq_desc[irq].status = IRQ_DISABLED;
                 irq_desc[irq].action = 0;
                 irq_desc[irq].depth = 1;
index d1da0d844567f66156bff7632a4c73012e466fbe..2955adc52310a8afedaa0fe868165d1d7c467403 100644 (file)
@@ -103,7 +103,7 @@ void __init init_cqreek_IRQ(void)
                cqreek_irq_data[14].stat_port = BRIDGE_IDE_INTR_STAT;
                cqreek_irq_data[14].bit = 1;
 
-               irq_desc[14].handler = &cqreek_irq_type;
+               irq_desc[14].chip = &cqreek_irq_type;
                irq_desc[14].status = IRQ_DISABLED;
                irq_desc[14].action = 0;
                irq_desc[14].depth = 1;
@@ -117,7 +117,7 @@ void __init init_cqreek_IRQ(void)
                cqreek_irq_data[10].bit = (1 << 10);
 
                /* XXX: Err... we may need demultiplexer for ISA irq... */
-               irq_desc[10].handler = &cqreek_irq_type;
+               irq_desc[10].chip = &cqreek_irq_type;
                irq_desc[10].status = IRQ_DISABLED;
                irq_desc[10].action = 0;
                irq_desc[10].depth = 1;
index 55dece35cde5c3be7c687a0eeab5ced10508ba06..0027b80a23435cfd005e45f255ddd62fd5801a52 100644 (file)
@@ -70,7 +70,7 @@ int __init platform_setup(void)
 
        /* Assign all virtual IRQs to the System ASIC int. handler */
        for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
-               irq_desc[i].handler = &systemasic_int;
+               irq_desc[i].chip = &systemasic_int;
 
        board_time_init = aica_time_init;
 
index 5130ba2b6ff1aeb95f2631f496a3a72c25d9e1e3..4b3ef16a0e960dc11d207966454e902dfc3e42c2 100644 (file)
@@ -63,7 +63,7 @@ int __init platform_setup(void)
                str[i] = ctrl_readb(EC3104_BASE + i);
 
        for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
-               irq_desc[i].handler = &ec3104_int;
+               irq_desc[i].chip = &ec3104_int;
 
        printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
               str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
index 52d0ba39031b7215a1a9c62dc3af49461c6f817f..701fa55d52978b25cc0f0067700e9fe49e1bdce8 100644 (file)
@@ -114,7 +114,7 @@ static void enable_harp_irq(unsigned int irq)
 static void __init make_harp_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &harp_irq_type;
+       irq_desc[irq].chip = &harp_irq_type;
        disable_harp_irq(irq);
 }
 
index ba3a6543975227fb6a40c3a6f93f18c3989a884c..9f7ccd33ffb603d76e8262af032ca93e87b03911 100644 (file)
@@ -273,9 +273,9 @@ void __init pcibios_fixup_irqs(void)
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
-       unsigned long start = res->start;
+       resource_size_t start = res->start;
 
        if (res->flags & IORESOURCE_IO) {
                if (start >= 0x10000UL) {
index 2bb581b916834749a71c0ff0c0e66996b51372e5..b72f009c52c26cee58fe5317adb246e83b1ac23d 100644 (file)
@@ -194,7 +194,7 @@ static struct hw_interrupt_type mpc1211_irq_type = {
 
 static void make_mpc1211_irq(unsigned int irq)
 {
-       irq_desc[irq].handler = &mpc1211_irq_type;
+       irq_desc[irq].chip = &mpc1211_irq_type;
        irq_desc[irq].status  = IRQ_DISABLED;
        irq_desc[irq].action  = 0;
        irq_desc[irq].depth   = 1;
index 276fa11ee4ce0c4ad581415c146217a825d68141..b055809d2ac1a4459befa360b5d20d4e632db8f1 100644 (file)
@@ -536,7 +536,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size)
+                           resource_size_t size)
 {
 }
 
index 715e8feb3a68783cc8d1b4375beb632db0f21a7d..2c13a7de6b22ada84a822b199b84cad8af6a4b7b 100644 (file)
@@ -150,7 +150,7 @@ static void enable_od_irq(unsigned int irq)
 static void __init make_od_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &od_irq_type;
+       irq_desc[irq].chip = &od_irq_type;
        disable_od_irq(irq);
 }
 
index ed4c5b50ea45edc29cb77c57f0731dfeda251f47..52a98b524e1fe6263522db00488974dd079046a2 100644 (file)
@@ -86,7 +86,7 @@ static struct hw_interrupt_type hs7751rvoip_irq_type = {
 static void make_hs7751rvoip_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &hs7751rvoip_irq_type;
+       irq_desc[irq].chip = &hs7751rvoip_irq_type;
        disable_hs7751rvoip_irq(irq);
 }
 
index d36c9374aed1dffc9daf9980a5a8439f3da2dd00..e16915d9cda440a3b6e754c6f90e0075eb608cf1 100644 (file)
@@ -100,7 +100,7 @@ static struct hw_interrupt_type rts7751r2d_irq_type = {
 static void make_rts7751r2d_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &rts7751r2d_irq_type;
+       irq_desc[irq].chip = &rts7751r2d_irq_type;
        disable_rts7751r2d_irq(irq);
 }
 
index 7a2eb10edb563c4b108b35204528b536aa1d6e45..845979181059e708cf68d9d902e9b626a1bc1a27 100644 (file)
@@ -105,7 +105,7 @@ static void end_systemh_irq(unsigned int irq)
 void make_systemh_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &systemh_irq_type;
+       irq_desc[irq].chip = &systemh_irq_type;
        disable_systemh_irq(irq);
 }
 
index 70f04caad9a414a1897eab2c585700bd9e8384fa..402735c7c89831cec484953cac01a8d3d5f8bb12 100644 (file)
@@ -85,7 +85,7 @@ void
 make_intreq_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &intreq_irq_type;
+       irq_desc[irq].chip = &intreq_irq_type;
        disable_intreq_irq(irq);
 }
 
index efcbd86b7cd2ff0c546671aaa318916f3ba15def..cb5999425d163641619ce4b403d10675c40e1b9a 100644 (file)
@@ -147,7 +147,7 @@ static void enable_microdev_irq(unsigned int irq)
 static void __init make_microdev_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &microdev_irq_type;
+       irq_desc[irq].chip = &microdev_irq_type;
        disable_microdev_irq(irq);
 }
 
index f014b9bf69224003bdbbb05ff62cfc0540e70e40..724db04cb3929acf6c53ae8ff343a5964045c10c 100644 (file)
@@ -154,7 +154,7 @@ int __init setup_hd64461(void)
        outw(0xffff, HD64461_NIMR);
 
        for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) {
-               irq_desc[i].handler = &hd64461_irq_type;
+               irq_desc[i].chip = &hd64461_irq_type;
        }
 
        setup_irq(CONFIG_HD64461_IRQ, &irq0);
index 68e4c4e4283dc6341b6cc20d63f8244c2766cb04..cf9142c620b7fbc7b30916dab36e02482fc2b10a 100644 (file)
@@ -182,7 +182,7 @@ static int __init setup_hd64465(void)
        outw(0xffff, HD64465_REG_NIMR);         /* mask all interrupts */
 
        for (i = 0; i < HD64465_IRQ_NUM ; i++) {
-               irq_desc[HD64465_IRQ_BASE + i].handler = &hd64465_irq_type;
+               irq_desc[HD64465_IRQ_BASE + i].chip = &hd64465_irq_type;
        }
 
        setup_irq(CONFIG_HD64465_IRQ, &irq0);
index 2ee330b3c38f68e5b2b3113ab1ffd56aaf54427e..892214bade194edf67e0387b435ef04b3c792e50 100644 (file)
@@ -191,7 +191,7 @@ void __init setup_voyagergx_irq(void)
                        flag = 1;
                }
                if (flag == 1)
-                       irq_desc[VOYAGER_IRQ_BASE + i].handler = &voyagergx_irq_type;
+                       irq_desc[VOYAGER_IRQ_BASE + i].chip = &voyagergx_irq_type;
        }
 
        setup_irq(IRQ_VOYAGER, &irq0);
index c1669905abe4d8e632fe823d48b0d0d5420aba27..3d546ba329cfb866a9457751f6ab888523b867cd 100644 (file)
@@ -75,7 +75,7 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
                            __attribute__ ((weak));
 
 /*
@@ -85,10 +85,10 @@ void pcibios_align_resource(void *data, struct resource *res,
  * modulo 0x400.
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
index baed9a550d39d9aff4223992b9db6d48b0eb4c5e..a33ae3e0a5a5dc808f72c425d69afca96d4ed531 100644 (file)
@@ -105,6 +105,6 @@ static void shutdown_imask_irq(unsigned int irq)
 void make_imask_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &imask_irq_type;
+       irq_desc[irq].chip = &imask_irq_type;
        enable_irq(irq);
 }
index 06e8afab32e438f75f49c83385229c6f9776a43d..30064bf6e154bf5f46a2f5c0cfea97bf50c616d4 100644 (file)
@@ -137,7 +137,7 @@ void make_intc2_irq(unsigned int irq,
 
        local_irq_restore(flags);
 
-       irq_desc[irq].handler = &intc2_irq_type;
+       irq_desc[irq].chip = &intc2_irq_type;
 
        disable_intc2_irq(irq);
 }
index e55150ed085619d5962e039e1ebb2a4fdc2e9b15..0373b65c77f9c452b9f9d60cb5ad9bf0cf2862be 100644 (file)
@@ -115,7 +115,7 @@ void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority)
        ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */
        ipr_data[irq].priority = priority;
 
-       irq_desc[irq].handler = &ipr_irq_type;
+       irq_desc[irq].chip = &ipr_irq_type;
        disable_ipr_irq(irq);
 }
 
index 95d6024fe1ae8b0c218ffd665b7b09d1abe05673..714963a25bbaaa7767ff86ad66adc6791724dcd4 100644 (file)
@@ -85,7 +85,7 @@ static void end_pint_irq(unsigned int irq)
 void make_pint_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &pint_irq_type;
+       irq_desc[irq].chip = &pint_irq_type;
        disable_pint_irq(irq);
 }
 
index 8437ea7430fe061cec70510f9f0f0bb66d2e5fb1..83a4f91bce5aefab58cfdbd06e6c27f438ac2161 100644 (file)
@@ -417,7 +417,6 @@ static struct file_operations sq_fops = {
 static struct miscdevice sq_dev = {
        .minor          = STORE_QUEUE_MINOR,
        .name           = "sq",
-       .devfs_name     = "cpu/sq",
        .fops           = &sq_fops,
 };
 
index b56e79632f241aaa28fb91935ef3dace2c69924c..c2e07f7f3496a45efa79b87be2cc953b2ebd49e0 100644 (file)
@@ -47,7 +47,7 @@ int show_interrupts(struct seq_file *p, void *v)
                        goto unlock;
                seq_printf(p, "%3d: ",i);
                seq_printf(p, "%10u ", kstat_irqs(i));
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index bb229ef030f3cbf70c5afa777cd50e194fed6025..9af22116c9a2b3a78e02c8533e59660769d95723 100644 (file)
@@ -402,7 +402,7 @@ static int __init topology_init(void)
        int cpu_id;
 
        for_each_possible_cpu(cpu_id)
-               register_cpu(&cpu[cpu_id], cpu_id, NULL);
+               register_cpu(&cpu[cpu_id], cpu_id);
 
        return 0;
 }
index d69879c0e063dc7ed39f890fd5020345f830a268..675776a5477e04d5e72dfcda1c02f42d61878d00 100644 (file)
@@ -65,7 +65,7 @@ int show_interrupts(struct seq_file *p, void *v)
                        goto unlock;
                seq_printf(p, "%3d: ",i);
                seq_printf(p, "%10u ", kstat_irqs(i));
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index fc99bf4e362c9dfca4dada4ff45263baa3f46a08..fa730f5fe2e6e6729ab1b9a2b19ae4c7556ecfc9 100644 (file)
@@ -178,7 +178,7 @@ static void end_intc_irq(unsigned int irq)
 void make_intc_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
-       irq_desc[irq].handler = &intc_irq_type;
+       irq_desc[irq].chip = &intc_irq_type;
        disable_intc_irq(irq);
 }
 
@@ -208,7 +208,7 @@ void __init init_IRQ(void)
        /* Set default: per-line enable/disable, priority driven ack/eoi */
        for (i = 0; i < NR_INTC_IRQS; i++) {
                if (platform_int_priority[i] != NO_PRIORITY) {
-                       irq_desc[i].handler = &intc_irq_type;
+                       irq_desc[i].chip = &intc_irq_type;
                }
        }
 
index 50c61dcb9faee7b79bcdc071ef79634d13bbda8e..945920bc24db62421f0948ada2ab91125644b96c 100644 (file)
@@ -69,10 +69,10 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
  * modulo 0x400.
  */
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
index d2711c9c9d13954dbadaecdf0665e7b3d06cdbe1..da98d8dbcf95324284de3d601e2364cc1923c896 100644 (file)
@@ -309,7 +309,7 @@ static struct cpu cpu[1];
 
 static int __init topology_init(void)
 {
-       return register_cpu(cpu, 0, NULL);
+       return register_cpu(cpu, 0);
 }
 
 subsys_initcall(topology_init);
index f797c84bfdd1e9dae8c26211d9ca2024e9297861..05eb7cdc26f0557921231486893d869338974eef 100644 (file)
@@ -187,7 +187,7 @@ void init_cayman_irq(void)
        }
 
        for (i=0; i<NR_EXT_IRQS; i++) {
-               irq_desc[START_EXT_IRQS + i].handler = &cayman_irq_type;
+               irq_desc[START_EXT_IRQS + i].chip = &cayman_irq_type;
        }
 
        /* Setup the SMSC interrupt */
index ae4c667c906f5caf0ef2d049bc5b35382330be03..79d177149fdb351825c750559a05a0f4b92b4094 100644 (file)
@@ -208,7 +208,7 @@ _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz)
        pa &= PAGE_MASK;
        sparc_mapiorange(bus, pa, res->start, res->end - res->start + 1);
 
-       return (void __iomem *) (res->start + offset);
+       return (void __iomem *)(unsigned long)(res->start + offset);
 }
 
 /*
@@ -325,7 +325,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
                res->name = sdev->prom_name;
        }
 
-       return (void *)res->start;
+       return (void *)(unsigned long)res->start;
 
 err_noiommu:
        release_resource(res);
@@ -819,7 +819,9 @@ _sparc_io_get_info(char *buf, char **start, off_t fpos, int length, int *eof,
                if (p + 32 >= e)        /* Better than nothing */
                        break;
                if ((nm = r->name) == 0) nm = "???";
-               p += sprintf(p, "%08lx-%08lx: %s\n", r->start, r->end, nm);
+               p += sprintf(p, "%016llx-%016llx: %s\n",
+                               (unsigned long long)r->start,
+                               (unsigned long long)r->end, nm);
        }
 
        return p-buf;
index bcfdddd0418aeda77ab17a87c46e8df5f16287d8..5df3ebdc0ab180b3cbffdfa5a3d9cdbebf33439b 100644 (file)
@@ -860,7 +860,7 @@ char * __init pcibios_setup(char *str)
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
 }
 
index a893a9cc953473a335668569407c0b8d7a35ccf1..2e5d08ce217b28104dc9e8ce9d49bec867ed5d9d 100644 (file)
@@ -496,7 +496,7 @@ static int __init topology_init(void)
                if (!p)
                        err = -ENOMEM;
                else
-                       register_cpu(p, i, NULL);
+                       register_cpu(p, i);
        }
 
        return err;
index cc89b06d01785a73ca974202da67f6852f52e9da..ab9e640df22820a5ffd9084b73258ea09042c41e 100644 (file)
@@ -151,7 +151,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %9s", irq_desc[i].handler->typename);
+               seq_printf(p, " %9s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -224,7 +224,7 @@ static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq)
 #ifdef CONFIG_SMP
 static int irq_choose_cpu(unsigned int virt_irq)
 {
-       cpumask_t mask = irq_affinity[virt_irq];
+       cpumask_t mask = irq_desc[virt_irq].affinity;
        int cpuid;
 
        if (cpus_equal(mask, CPU_MASK_ALL)) {
@@ -414,8 +414,8 @@ void irq_install_pre_handler(int virt_irq,
        data->pre_handler_arg1 = arg1;
        data->pre_handler_arg2 = arg2;
 
-       desc->handler = (desc->handler == &sun4u_irq ?
-                        &sun4u_irq_ack : &sun4v_irq_ack);
+       desc->chip = (desc->chip == &sun4u_irq ?
+                     &sun4u_irq_ack : &sun4v_irq_ack);
 }
 
 unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
@@ -431,7 +431,7 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
        bucket = &ivector_table[ino];
        if (!bucket->virt_irq) {
                bucket->virt_irq = virt_irq_alloc(__irq(bucket));
-               irq_desc[bucket->virt_irq].handler = &sun4u_irq;
+               irq_desc[bucket->virt_irq].chip = &sun4u_irq;
        }
 
        desc = irq_desc + bucket->virt_irq;
@@ -465,7 +465,7 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
        bucket = &ivector_table[sysino];
        if (!bucket->virt_irq) {
                bucket->virt_irq = virt_irq_alloc(__irq(bucket));
-               irq_desc[bucket->virt_irq].handler = &sun4v_irq;
+               irq_desc[bucket->virt_irq].chip = &sun4v_irq;
        }
 
        desc = irq_desc + bucket->virt_irq;
index 6c9e3e94abaa74a68fb06f05f9ba857c0721661f..20ca9ec8fd3bbef18c844490c4f8f553c9a23116 100644 (file)
@@ -357,7 +357,7 @@ void pcibios_update_irq(struct pci_dev *pdev, int irq)
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size, unsigned long align)
+                           resource_size_t size, resource_size_t align)
 {
 }
 
index a6a7d8168346c6b50b9910727ccd344f9566b5f1..116d9632002defd035dfdae91f0d80767d75d3b6 100644 (file)
@@ -537,7 +537,7 @@ static int __init topology_init(void)
        for_each_possible_cpu(i) {
                struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
                if (p) {
-                       register_cpu(p, i, NULL);
+                       register_cpu(p, i);
                        err = 0;
                }
        }
index 5c2bcf354ce64aa3d74ad75dbc7a7eb0ba0091bd..cb75a27adb517bba8b2d43289b0cb8e1a64ef81d 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/initrd.h>
 #include <linux/swap.h>
 #include <linux/pagemap.h>
+#include <linux/poison.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
 #include <linux/kprobes.h>
@@ -1520,7 +1521,7 @@ void free_initmem(void)
                page = (addr +
                        ((unsigned long) __va(kern_base)) -
                        ((unsigned long) KERNBASE));
-               memset((void *)addr, 0xcc, PAGE_SIZE);
+               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
                p = virt_to_page(page);
 
                ClearPageReserved(p);
index fc6669e8dde189640a053c40f629e63720795d9c..bc3df95bc05773b9a74419c6692f342dd9005120 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/in.h>
-#include <linux/devfs_fs_kernel.h>
 
 #include <net/sock.h>
 
@@ -190,8 +189,6 @@ init_socksys(void)
                return ret;
        }
 
-       devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUSR|S_IWUSR, "socksys");
-
        file = fcheck(ret);
        /* N.B. Is this valid? Suppose the f_ops are in a module ... */
        socksys_file_ops = *file->f_op;
@@ -207,5 +204,4 @@ cleanup_socksys(void)
 {
        if (unregister_chrdev(30, "socksys"))
                printk ("Couldn't unregister socksys character device\n");
-       devfs_remove ("socksys");
 }
index 6c2d4ccaf20f63cc59ed049e4f960bf546665af6..5ca57ca337136034799e3dad4df7d733802dc4bc 100644 (file)
@@ -8,7 +8,6 @@
 #include "linux/list.h"
 #include "linux/kd.h"
 #include "linux/interrupt.h"
-#include "linux/devfs_fs_kernel.h"
 #include "asm/uaccess.h"
 #include "chan_kern.h"
 #include "irq_user.h"
@@ -655,7 +654,6 @@ struct tty_driver *line_register_devfs(struct lines *set,
 
        driver->driver_name = line_driver->name;
        driver->name = line_driver->device_name;
-       driver->devfs_name = line_driver->devfs_name;
        driver->major = line_driver->major;
        driver->minor_start = line_driver->minor_start;
        driver->type = line_driver->type;
index a4d6415bc8c4820340a299a58e7b340ee33cbcf0..6dafd6fbfdaed13be0f48424f1e811fd24955b89 100644 (file)
@@ -54,7 +54,6 @@ static int ssl_remove(int n);
 static struct line_driver driver = {
        .name                   = "UML serial line",
        .device_name            = "ttyS",
-       .devfs_name             = "tts/",
        .major                  = TTY_MAJOR,
        .minor_start            = 64,
        .type                   = TTY_DRIVER_TYPE_SERIAL,
index 61db8b2fc83f5780624a92e2510812db891dd36e..856f568c2687fd485a111d2f68843bb3918ac7dc 100644 (file)
@@ -60,7 +60,6 @@ static int con_remove(int n);
 static struct line_driver driver = {
        .name                   = "UML console",
        .device_name            = "tty",
-       .devfs_name             = "vc/",
        .major                  = TTY_MAJOR,
        .minor_start            = 0,
        .type                   = TTY_DRIVER_TYPE_CONSOLE,
index 290cec6d69e23e8981b570d973a5800ddf2993fd..0345e255124798d3f26965a327b6e44ce701fa0a 100644 (file)
@@ -25,7 +25,6 @@
 #include "linux/blkdev.h"
 #include "linux/hdreg.h"
 #include "linux/init.h"
-#include "linux/devfs_fs_kernel.h"
 #include "linux/cdrom.h"
 #include "linux/proc_fs.h"
 #include "linux/ctype.h"
@@ -628,7 +627,6 @@ static int ubd_new_disk(int major, u64 size, int unit,
                        
 {
        struct gendisk *disk;
-       char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")];
        int err;
 
        disk = alloc_disk(1 << UBD_SHIFT);
@@ -639,20 +637,10 @@ static int ubd_new_disk(int major, u64 size, int unit,
        disk->first_minor = unit << UBD_SHIFT;
        disk->fops = &ubd_blops;
        set_capacity(disk, size / 512);
-       if(major == MAJOR_NR){
+       if(major == MAJOR_NR)
                sprintf(disk->disk_name, "ubd%c", 'a' + unit);
-               sprintf(disk->devfs_name, "ubd/disc%d", unit);
-               sprintf(from, "ubd/%d", unit);
-               sprintf(to, "disc%d/disc", unit);
-               err = devfs_mk_symlink(from, to);
-               if(err)
-                       printk("ubd_new_disk failed to make link from %s to "
-                              "%s, error = %d\n", from, to, err);
-       }
-       else {
+       else
                sprintf(disk->disk_name, "ubd_fake%d", unit);
-               sprintf(disk->devfs_name, "ubd_fake/disc%d", unit);
-       }
 
        /* sysfs register (not for ide fake devices) */
        if (major == MAJOR_NR) {
@@ -841,7 +829,6 @@ int ubd_init(void)
 {
         int i;
 
-       devfs_mk_dir("ubd");
        if (register_blkdev(MAJOR_NR, "ubd"))
                return -1;
 
@@ -855,7 +842,6 @@ int ubd_init(void)
                char name[sizeof("ubd_nnn\0")];
 
                snprintf(name, sizeof(name), "ubd_%d", fake_major);
-               devfs_mk_dir(name);
                if (register_blkdev(fake_major, "ubd"))
                        return -1;
        }
index 6ac0f8252e21e3dfdf55d359c0d46c8f7dbc069a..27bf2f6fbc05a60d398cb9b2b8ef0a51605711b2 100644 (file)
@@ -17,7 +17,6 @@
 struct line_driver {
        char *name;
        char *device_name;
-       char *devfs_name;
        short major;
        short minor_start;
        short type;
index 2ffda012385e9e5f9f3f15be42389f42c3e1164c..fae43a3054a0bec3c00782e70e66926186a28e8c 100644 (file)
@@ -63,7 +63,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -451,13 +451,13 @@ void __init init_IRQ(void)
        irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
        irq_desc[TIMER_IRQ].action = NULL;
        irq_desc[TIMER_IRQ].depth = 1;
-       irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;
+       irq_desc[TIMER_IRQ].chip = &SIGVTALRM_irq_type;
        enable_irq(TIMER_IRQ);
        for (i = 1; i < NR_IRQS; i++) {
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &normal_irq_type;
+               irq_desc[i].chip = &normal_irq_type;
                enable_irq(i);
        }
 }
index 7a151c26f82e2bd7be47a0053deb18bf84f0004d..858c45819aabe496dd663eb27195ea3d835b4f1c 100644 (file)
@@ -65,10 +65,10 @@ int show_interrupts(struct seq_file *p, void *v)
                        int j;
                        int count = 0;
                        int num = -1;
-                       const char *type_name = irq_desc[irq].handler->typename;
+                       const char *type_name = irq_desc[irq].chip->typename;
 
                        for (j = 0; j < NR_IRQS; j++)
-                               if (irq_desc[j].handler->typename == type_name){
+                               if (irq_desc[j].chip->typename == type_name){
                                        if (irq == j)
                                                num = count;
                                        count++;
@@ -117,7 +117,7 @@ init_irq_handlers (int base_irq, int num, int interval,
                irq_desc[base_irq].status  = IRQ_DISABLED;
                irq_desc[base_irq].action  = NULL;
                irq_desc[base_irq].depth   = 1;
-               irq_desc[base_irq].handler = irq_type;
+               irq_desc[base_irq].chip = irq_type;
                base_irq += interval;
        }
 }
index ffbb6d073bf2b39e9f24814662d6a6129a132171..3a7c5c9c3ac66f5fd248c81d823e582dadcce1e9 100644 (file)
@@ -329,7 +329,7 @@ void pcibios_fixup_bus(struct pci_bus *b)
 
 void
 pcibios_align_resource (void *data, struct resource *res,
-                       unsigned long size, unsigned long align)
+                       resource_size_t size, resource_size_t align)
 {
 }
 
index ccc4a7fb97a370f8d56baf16e4eb1439a17621d3..e856804c447f4496c4c490b67a3e40b39baee5e3 100644 (file)
@@ -370,6 +370,8 @@ config HOTPLUG_CPU
                can be controlled through /sys/devices/system/cpu/cpu#.
                Say N if you want to disable CPU hotplug.
 
+config ARCH_ENABLE_MEMORY_HOTPLUG
+       def_bool y
 
 config HPET_TIMER
        bool
@@ -459,10 +461,10 @@ config KEXEC
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
-         but it is indepedent of the system firmware.   And like a reboot
+         but it is independent of the system firmware.   And like a reboot
          you can start any kernel with it, not just Linux.
 
-         The name comes from the similiarity to the exec system call.
+         The name comes from the similarity to the exec system call.
 
          It is an ongoing process to be certain the hardware in a machine
          is properly shutdown, so do not be surprised if this code does not
index 7290e72b9a34d2a56be1a90e3c96989d9df1d844..22cac4487b57fd1e9aef98769071a8e4f02f0d81 100644 (file)
@@ -588,7 +588,7 @@ END(common_interrupt)
  */            
        .macro apicinterrupt num,func
        INTR_FRAME
-       pushq $\num-256
+       pushq $~(\num)
        CFI_ADJUST_CFA_OFFSET 8
        interrupt \func
        jmp ret_from_intr
index 86b2c1e197aa3f6b1b86c7537aa7d42c6959bcc8..3dd1659427dc3a78f6c09c3e2827d36278f2b1e7 100644 (file)
@@ -235,7 +235,7 @@ void make_8259A_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
        io_apic_irqs &= ~(1<<irq);
-       irq_desc[irq].handler = &i8259A_irq_type;
+       irq_desc[irq].chip = &i8259A_irq_type;
        enable_irq(irq);
 }
 
@@ -468,12 +468,12 @@ void __init init_ISA_irqs (void)
                        /*
                         * 16 old-style INTA-cycle interrupts:
                         */
-                       irq_desc[i].handler = &i8259A_irq_type;
+                       irq_desc[i].chip = &i8259A_irq_type;
                } else {
                        /*
                         * 'high' PCI IRQs filled in on demand
                         */
-                       irq_desc[i].handler = &no_irq_type;
+                       irq_desc[i].chip = &no_irq_type;
                }
        }
 }
index c768d8a036d0c7998e802944f4cc0103e4ec0dbc..401b687fef21b2f4736c6a79d3f51b1fa1ac99b8 100644 (file)
@@ -876,15 +876,17 @@ static struct hw_interrupt_type ioapic_edge_type;
 #define IOAPIC_EDGE    0
 #define IOAPIC_LEVEL   1
 
-static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
+static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
-       unsigned idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
+       unsigned idx;
+
+       idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
 
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
                        trigger == IOAPIC_LEVEL)
-               irq_desc[idx].handler = &ioapic_level_type;
+               irq_desc[idx].chip = &ioapic_level_type;
        else
-               irq_desc[idx].handler = &ioapic_edge_type;
+               irq_desc[idx].chip = &ioapic_edge_type;
        set_intr_gate(vector, interrupt[idx]);
 }
 
@@ -986,7 +988,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
         * The timer IRQ doesn't have to know that behind the
         * scene we have a 8259A-master in AEOI mode ...
         */
-       irq_desc[0].handler = &ioapic_edge_type;
+       irq_desc[0].chip = &ioapic_edge_type;
 
        /*
         * Add it to the IO-APIC irq-routing table:
@@ -1616,6 +1618,13 @@ static void set_ioapic_affinity_vector (unsigned int vector,
 #endif // CONFIG_SMP
 #endif // CONFIG_PCI_MSI
 
+static int ioapic_retrigger(unsigned int irq)
+{
+       send_IPI_self(IO_APIC_VECTOR(irq));
+
+       return 1;
+}
+
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
  * so we use two separate IRQ descriptors. Edge triggered IRQs can be
@@ -1636,6 +1645,7 @@ static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
 #ifdef CONFIG_SMP
        .set_affinity = set_ioapic_affinity,
 #endif
+       .retrigger      = ioapic_retrigger,
 };
 
 static struct hw_interrupt_type ioapic_level_type __read_mostly = {
@@ -1649,6 +1659,7 @@ static struct hw_interrupt_type ioapic_level_type __read_mostly = {
 #ifdef CONFIG_SMP
        .set_affinity = set_ioapic_affinity,
 #endif
+       .retrigger      = ioapic_retrigger,
 };
 
 static inline void init_IO_APIC_traps(void)
@@ -1683,7 +1694,7 @@ static inline void init_IO_APIC_traps(void)
                                make_8259A_irq(irq);
                        else
                                /* Strange. Oh, well.. */
-                               irq_desc[irq].handler = &no_irq_type;
+                               irq_desc[irq].chip = &no_irq_type;
                }
        }
 }
@@ -1900,7 +1911,7 @@ static inline void check_timer(void)
        apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
        disable_8259A_irq(0);
-       irq_desc[0].handler = &lapic_irq_type;
+       irq_desc[0].chip = &lapic_irq_type;
        apic_write(APIC_LVT0, APIC_DM_FIXED | vector);  /* Fixed mode */
        enable_8259A_irq(0);
 
index 59518d4d43589a9b99724ecefbd6b6162b43ac28..a1f1df5f7bfc2d5a40d6269e5a37f69d6dc746af 100644 (file)
@@ -79,7 +79,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
 
                seq_printf(p, "  %s", action->name);
                for (action=action->next; action; action = action->next)
@@ -115,8 +115,14 @@ skip:
  */
 asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
 {      
-       /* high bits used in ret_from_ code  */
-       unsigned irq = regs->orig_rax & 0xff;
+       /* high bit used in ret_from_ code  */
+       unsigned irq = ~regs->orig_rax;
+
+       if (unlikely(irq >= NR_IRQS)) {
+               printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
+                                       __FUNCTION__, irq);
+               BUG();
+       }
 
        exit_idle();
        irq_enter();
@@ -140,13 +146,13 @@ void fixup_irqs(cpumask_t map)
                if (irq == 2)
                        continue;
 
-               cpus_and(mask, irq_affinity[irq], map);
+               cpus_and(mask, irq_desc[irq].affinity, map);
                if (any_online_cpu(mask) == NR_CPUS) {
                        printk("Breaking affinity for irq %i\n", irq);
                        mask = map;
                }
-               if (irq_desc[irq].handler->set_affinity)
-                       irq_desc[irq].handler->set_affinity(irq, mask);
+               if (irq_desc[irq].chip->set_affinity)
+                       irq_desc[irq].chip->set_affinity(irq, mask);
                else if (irq_desc[irq].action && !(warned++))
                        printk("Cannot set affinity for irq %i\n", irq);
        }
index acd5816b1a6f214d2dfc5253d674ed9d81492fe5..88845674c661a39feefc5b35bb5c5dd9b2255be8 100644 (file)
@@ -629,7 +629,7 @@ static __cpuinit void mce_remove_device(unsigned int cpu)
 #endif
 
 /* Get notified when a cpu comes on/off. Be hotplug friendly. */
-static int
+static __cpuinit int
 mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
@@ -647,7 +647,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
-static struct notifier_block mce_cpu_notifier = {
+static struct notifier_block __cpuinitdata mce_cpu_notifier = {
        .notifier_call = mce_cpu_callback,
 };
 
index 399489c93132c2b9c3d6954b9b2d7149ad084f63..0ef9cf2bc45e4ea809e3a76fb2c4f61dc4a3c7b4 100644 (file)
@@ -607,11 +607,13 @@ void set_nmi_callback(nmi_callback_t callback)
        vmalloc_sync_all();
        rcu_assign_pointer(nmi_callback, callback);
 }
+EXPORT_SYMBOL_GPL(set_nmi_callback);
 
 void unset_nmi_callback(void)
 {
        nmi_callback = dummy_nmi_callback;
 }
+EXPORT_SYMBOL_GPL(unset_nmi_callback);
 
 #ifdef CONFIG_SYSCTL
 
index acee4bc3f6fa945799d194b17cfbf4cac20285e6..5a1c0a3bf87262c027c327773628e93e58194188 100644 (file)
@@ -135,10 +135,10 @@ asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs)
 
        cpu = smp_processor_id();
        /*
-        * orig_rax contains the interrupt vector - 256.
+        * orig_rax contains the negated interrupt vector.
         * Use that to determine where the sender put the data.
         */
-       sender = regs->orig_rax + 256 - INVALIDATE_TLB_VECTOR_START;
+       sender = ~regs->orig_rax - INVALIDATE_TLB_VECTOR_START;
        f = &per_cpu(flush_state, sender);
 
        if (!cpu_isset(cpu, f->flush_cpumask))
index 4e9755179ecf57022bcb8e4e6adaa76d62612010..540c0ccbcccc8953c95ee6b6c2baf5ad11e44aaf 100644 (file)
@@ -455,10 +455,12 @@ cpumask_t cpu_coregroup_map(int cpu)
        struct cpuinfo_x86 *c = cpu_data + cpu;
        /*
         * For perf, we return last level cache shared map.
-        * TBD: when power saving sched policy is added, we will return
-        *      cpu_core_map when power saving policy is enabled
+        * And for power savings, we return cpu_core_map
         */
-       return c->llc_shared_map;
+       if (sched_mc_power_savings || sched_smt_power_savings)
+               return cpu_core_map[cpu];
+       else
+               return c->llc_shared_map;
 }
 
 /* representing cpus for which sibling maps can be computed */
index 02add1d1dfa88aa0843b0fffc245399fd5e4adbf..95bd232ff0cf3d37fc3b5838e0b477666115aebb 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/bootmem.h>
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
+#include <linux/poison.h>
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/memory_hotplug.h>
@@ -506,8 +507,6 @@ void __init clear_kernel_mapping(unsigned long address, unsigned long size)
 /*
  * Memory hotplug specific functions
  */
-#if defined(CONFIG_ACPI_HOTPLUG_MEMORY) || defined(CONFIG_ACPI_HOTPLUG_MEMORY_MODULE)
-
 void online_page(struct page *page)
 {
        ClearPageReserved(page);
@@ -517,31 +516,17 @@ void online_page(struct page *page)
        num_physpages++;
 }
 
-#ifndef CONFIG_MEMORY_HOTPLUG
+#ifdef CONFIG_MEMORY_HOTPLUG
 /*
- * Memory Hotadd without sparsemem. The mem_maps have been allocated in advance,
- * just online the pages.
+ * XXX: memory_add_physaddr_to_nid() is to find node id from physical address
+ *     via probe interface of sysfs. If acpi notifies hot-add event, then it
+ *     can tell node id by searching dsdt. But, probe interface doesn't have
+ *     node id. So, return 0 as node id at this time.
  */
-int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages)
+#ifdef CONFIG_NUMA
+int memory_add_physaddr_to_nid(u64 start)
 {
-       int err = -EIO;
-       unsigned long pfn;
-       unsigned long total = 0, mem = 0;
-       for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++) {
-               if (pfn_valid(pfn)) {
-                       online_page(pfn_to_page(pfn));
-                       err = 0;
-                       mem++;
-               }
-               total++;
-       }
-       if (!err) {
-               z->spanned_pages += total;
-               z->present_pages += mem;
-               z->zone_pgdat->node_spanned_pages += total;
-               z->zone_pgdat->node_present_pages += mem;
-       }
-       return err;
+       return 0;
 }
 #endif
 
@@ -549,9 +534,9 @@ int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages)
  * Memory is added always to NORMAL zone. This means you will never get
  * additional DMA/DMA32 memory.
  */
-int add_memory(u64 start, u64 size)
+int arch_add_memory(int nid, u64 start, u64 size)
 {
-       struct pglist_data *pgdat = NODE_DATA(0);
+       struct pglist_data *pgdat = NODE_DATA(nid);
        struct zone *zone = pgdat->node_zones + MAX_NR_ZONES-2;
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
@@ -568,7 +553,7 @@ error:
        printk("%s: Problem encountered in __add_pages!\n", __func__);
        return ret;
 }
-EXPORT_SYMBOL_GPL(add_memory);
+EXPORT_SYMBOL_GPL(arch_add_memory);
 
 int remove_memory(u64 start, u64 size)
 {
@@ -576,7 +561,33 @@ int remove_memory(u64 start, u64 size)
 }
 EXPORT_SYMBOL_GPL(remove_memory);
 
-#endif
+#else /* CONFIG_MEMORY_HOTPLUG */
+/*
+ * Memory Hotadd without sparsemem. The mem_maps have been allocated in advance,
+ * just online the pages.
+ */
+int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages)
+{
+       int err = -EIO;
+       unsigned long pfn;
+       unsigned long total = 0, mem = 0;
+       for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++) {
+               if (pfn_valid(pfn)) {
+                       online_page(pfn_to_page(pfn));
+                       err = 0;
+                       mem++;
+               }
+               total++;
+       }
+       if (!err) {
+               z->spanned_pages += total;
+               z->present_pages += mem;
+               z->zone_pgdat->node_spanned_pages += total;
+               z->zone_pgdat->node_present_pages += mem;
+       }
+       return err;
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */
 
 static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules,
                         kcore_vsyscall;
@@ -650,7 +661,8 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
        for (addr = begin; addr < end; addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
                init_page_count(virt_to_page(addr));
-               memset((void *)(addr & ~(PAGE_SIZE-1)), 0xcc, PAGE_SIZE); 
+               memset((void *)(addr & ~(PAGE_SIZE-1)),
+                       POISON_FREE_INITMEM, PAGE_SIZE);
                free_page(addr);
                totalram_pages++;
        }
@@ -658,7 +670,8 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
 
 void free_initmem(void)
 {
-       memset(__initdata_begin, 0xba, __initdata_end - __initdata_begin);
+       memset(__initdata_begin, POISON_FREE_INITDATA,
+               __initdata_end - __initdata_begin);
        free_init_pages("unused kernel memory",
                        (unsigned long)(&__init_begin),
                        (unsigned long)(&__init_end));
index 51f9bed455fab0c0576933a7702efb0d51cb84f4..1cf744ee0959e2515d5c47ebcbaffb9e6ac9fba3 100644 (file)
@@ -100,7 +100,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].handler->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->typename);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -181,7 +181,7 @@ void __init init_IRQ(void)
        int i;
 
        for (i=0; i < XTENSA_NR_IRQS; i++)
-               irq_desc[i].handler = &xtensa_irq_type;
+               irq_desc[i].chip = &xtensa_irq_type;
 
        cached_irq_mask = 0;
 
index c6f471b9eaa0c603f356441bea6b980c2e85492e..eda029fc897218a53d38a4f82a66db0a42272963 100644 (file)
@@ -71,13 +71,13 @@ static int pci_bus_count;
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size,
-                      unsigned long align)
+pcibios_align_resource(void *data, struct resource *res, resource_size_t size,
+                      resource_size_t align)
 {
        struct pci_dev *dev = data;
 
        if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
+               resource_size_t start = res->start;
 
                if (size > 0x100) {
                        printk(KERN_ERR "PCI: I/O Region %s/%d too large"
index 937d81f62f43e73e90e75e1280a0ef899cbbadbe..fe14909f45e057983c1100c5dab33359d718d7c6 100644 (file)
@@ -29,7 +29,7 @@
 
 extern volatile unsigned long wall_jiffies;
 
-spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 
 
index 225d64d73f04c8700f9dc939bcbb26b0e56bf3e5..27e409089a7b9837ce33927236f21ea89323fdf1 100644 (file)
@@ -461,7 +461,7 @@ void show_code(unsigned int *pc)
        }
 }
 
-spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
index c04422a502da8ebd0cb03cc76d5962433fde6b0b..eee03a3876a3f2f875260b64c1c0bc51267219a3 100644 (file)
@@ -3403,7 +3403,7 @@ static int blk_cpu_notify(struct notifier_block *self, unsigned long action,
 }
 
 
-static struct notifier_block blk_cpu_notifier = {
+static struct notifier_block __devinitdata blk_cpu_notifier = {
        .notifier_call  = blk_cpu_notify,
 };
 
@@ -3541,9 +3541,7 @@ int __init blk_dev_init(void)
                INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
 
        open_softirq(BLOCK_SOFTIRQ, blk_done_softirq, NULL);
-#ifdef CONFIG_HOTPLUG_CPU
-       register_cpu_notifier(&blk_cpu_notifier);
-#endif
+       register_hotcpu_notifier(&blk_cpu_notifier);
 
        blk_max_low_pfn = max_low_pfn;
        blk_max_pfn = max_pfn;
index ce15aed1df3fcf1439f8f16c8db5c5f07ff2953a..bc2652d72fdc79dd97d1b2cd531e272e899caee4 100644 (file)
@@ -335,7 +335,7 @@ config ACPI_CONTAINER
 config ACPI_HOTPLUG_MEMORY
        tristate "Memory Hotplug"
        depends on ACPI
-       depends on MEMORY_HOTPLUG || X86_64
+       depends on MEMORY_HOTPLUG
        default n
        help
          This driver adds supports for ACPI Memory Hotplug.  This driver
index b0546951384261fabb8bec4f6f1d1e002fd228da..6f5e395c78af6f009ac6bc0b79d427471ebb1273 100644 (file)
@@ -57,6 +57,7 @@ MODULE_LICENSE("GPL");
 
 static int acpi_memory_device_add(struct acpi_device *device);
 static int acpi_memory_device_remove(struct acpi_device *device, int type);
+static int acpi_memory_device_start(struct acpi_device *device);
 
 static struct acpi_driver acpi_memory_device_driver = {
        .name = ACPI_MEMORY_DEVICE_DRIVER_NAME,
@@ -65,46 +66,77 @@ static struct acpi_driver acpi_memory_device_driver = {
        .ops = {
                .add = acpi_memory_device_add,
                .remove = acpi_memory_device_remove,
+               .start = acpi_memory_device_start,
                },
 };
 
+struct acpi_memory_info {
+       struct list_head list;
+       u64 start_addr;         /* Memory Range start physical addr */
+       u64 length;             /* Memory Range length */
+       unsigned short caching; /* memory cache attribute */
+       unsigned short write_protect;   /* memory read/write attribute */
+       unsigned int enabled:1;
+};
+
 struct acpi_memory_device {
        acpi_handle handle;
        unsigned int state;     /* State of the memory device */
-       unsigned short caching; /* memory cache attribute */
-       unsigned short write_protect;   /* memory read/write attribute */
-       u64 start_addr;         /* Memory Range start physical addr */
-       u64 length;             /* Memory Range length */
+       struct list_head res_list;
 };
 
+static acpi_status
+acpi_memory_get_resource(struct acpi_resource *resource, void *context)
+{
+       struct acpi_memory_device *mem_device = context;
+       struct acpi_resource_address64 address64;
+       struct acpi_memory_info *info, *new;
+       acpi_status status;
+
+       status = acpi_resource_to_address64(resource, &address64);
+       if (ACPI_FAILURE(status) ||
+           (address64.resource_type != ACPI_MEMORY_RANGE))
+               return AE_OK;
+
+       list_for_each_entry(info, &mem_device->res_list, list) {
+               /* Can we combine the resource range information? */
+               if ((info->caching == address64.info.mem.caching) &&
+                   (info->write_protect == address64.info.mem.write_protect) &&
+                   (info->start_addr + info->length == address64.minimum)) {
+                       info->length += address64.address_length;
+                       return AE_OK;
+               }
+       }
+
+       new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL);
+       if (!new)
+               return AE_ERROR;
+
+       INIT_LIST_HEAD(&new->list);
+       new->caching = address64.info.mem.caching;
+       new->write_protect = address64.info.mem.write_protect;
+       new->start_addr = address64.minimum;
+       new->length = address64.address_length;
+       list_add_tail(&new->list, &mem_device->res_list);
+
+       return AE_OK;
+}
+
 static int
 acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
 {
        acpi_status status;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_resource *resource = NULL;
-       struct acpi_resource_address64 address64;
+       struct acpi_memory_info *info, *n;
 
 
-       /* Get the range from the _CRS */
-       status = acpi_get_current_resources(mem_device->handle, &buffer);
-       if (ACPI_FAILURE(status))
+       status = acpi_walk_resources(mem_device->handle, METHOD_NAME__CRS,
+                                    acpi_memory_get_resource, mem_device);
+       if (ACPI_FAILURE(status)) {
+               list_for_each_entry_safe(info, n, &mem_device->res_list, list)
+                       kfree(info);
                return -EINVAL;
-
-       resource = (struct acpi_resource *)buffer.pointer;
-       status = acpi_resource_to_address64(resource, &address64);
-       if (ACPI_SUCCESS(status)) {
-               if (address64.resource_type == ACPI_MEMORY_RANGE) {
-                       /* Populate the structure */
-                       mem_device->caching = address64.info.mem.caching;
-                       mem_device->write_protect =
-                           address64.info.mem.write_protect;
-                       mem_device->start_addr = address64.minimum;
-                       mem_device->length = address64.address_length;
-               }
        }
 
-       acpi_os_free(buffer.pointer);
        return 0;
 }
 
@@ -177,7 +209,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
 
 static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
 {
-       int result;
+       int result, num_enabled = 0;
+       struct acpi_memory_info *info;
+       int node;
 
 
        /* Get the range from the _CRS */
@@ -188,15 +222,35 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
                return result;
        }
 
+       node = acpi_get_node(mem_device->handle);
        /*
         * Tell the VM there is more memory here...
         * Note: Assume that this function returns zero on success
+        * We don't have memory-hot-add rollback function,now.
+        * (i.e. memory-hot-remove function)
         */
-       result = add_memory(mem_device->start_addr, mem_device->length);
-       if (result) {
-               printk(KERN_ERR PREFIX "add_memory failed\n");
+       list_for_each_entry(info, &mem_device->res_list, list) {
+               u64 start_pfn, end_pfn;
+
+               start_pfn = info->start_addr >> PAGE_SHIFT;
+               end_pfn = (info->start_addr + info->length - 1) >> PAGE_SHIFT;
+
+               if (pfn_valid(start_pfn) || pfn_valid(end_pfn)) {
+                       /* already enabled. try next area */
+                       num_enabled++;
+                       continue;
+               }
+
+               result = add_memory(node, info->start_addr, info->length);
+               if (result)
+                       continue;
+               info->enabled = 1;
+               num_enabled++;
+       }
+       if (!num_enabled) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n"));
                mem_device->state = MEMORY_INVALID_STATE;
-               return result;
+               return -EINVAL;
        }
 
        return result;
@@ -239,17 +293,21 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
 static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
 {
        int result;
-       u64 start = mem_device->start_addr;
-       u64 len = mem_device->length;
+       struct acpi_memory_info *info, *n;
 
 
        /*
         * Ask the VM to offline this memory range.
         * Note: Assume that this function returns zero on success
         */
-       result = remove_memory(start, len);
-       if (result)
-               return result;
+       list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
+               if (info->enabled) {
+                       result = remove_memory(info->start_addr, info->length);
+                       if (result)
+                               return result;
+               }
+               kfree(info);
+       }
 
        /* Power-off and eject the device */
        result = acpi_memory_powerdown_device(mem_device);
@@ -339,6 +397,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
                return -ENOMEM;
        memset(mem_device, 0, sizeof(struct acpi_memory_device));
 
+       INIT_LIST_HEAD(&mem_device->res_list);
        mem_device->handle = device->handle;
        sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
        sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
@@ -373,6 +432,23 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+static int acpi_memory_device_start (struct acpi_device *device)
+{
+       struct acpi_memory_device *mem_device;
+       int result = 0;
+
+       mem_device = acpi_driver_data(device);
+
+       if (!acpi_memory_check_device(mem_device)) {
+               /* call add_memory func */
+               result = acpi_memory_enable_device(mem_device);
+               if (result)
+                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                               "Error in acpi_memory_enable_device\n"));
+       }
+       return result;
+}
+
 /*
  * Helper function to check for memory device
  */
index e2c1a16078c990113d4813024e0abf170e04928b..13d6d5bdea264f16dbe6239d2cde0a5b5d5daa20 100644 (file)
@@ -254,5 +254,18 @@ int acpi_get_pxm(acpi_handle h)
        } while (ACPI_SUCCESS(status));
        return -1;
 }
-
 EXPORT_SYMBOL(acpi_get_pxm);
+
+int acpi_get_node(acpi_handle *handle)
+{
+       int pxm, node = -1;
+
+       ACPI_FUNCTION_TRACE("acpi_get_node");
+
+       pxm = acpi_get_pxm(handle);
+       if (pxm >= 0)
+               node = acpi_map_pxm_to_node(pxm);
+
+       return_VALUE(node);
+}
+EXPORT_SYMBOL(acpi_get_node);
index 889855d8d9f9080ee9b98c3a1a1bcd0691006f59..9e3e2a69c03a6dedd375b32666e94b0989ed1566 100644 (file)
@@ -180,8 +180,9 @@ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
 amba_attr(id, "%08x\n", dev->periphid);
 amba_attr(irq0, "%u\n", dev->irq[0]);
 amba_attr(irq1, "%u\n", dev->irq[1]);
-amba_attr(resource, "\t%08lx\t%08lx\t%08lx\n",
-         dev->res.start, dev->res.end, dev->res.flags);
+amba_attr(resource, "\t%016llx\t%016llx\t%016lx\n",
+        (unsigned long long)dev->res.start, (unsigned long long)dev->res.end,
+        dev->res.flags);
 
 /**
  *     amba_device_register - register an AMBA device
index 4b6bf19c39c004d4b2277f11e68ac2ea59a4b753..4048681f36d503ca2030d0954311ce97327cc183 100644 (file)
@@ -2257,7 +2257,8 @@ static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_
        }
 
        PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at"
-               " IO %lx, IRQ %u, MEM %p", pci_resource_start(pci_dev, 1),
+               " IO %llx, IRQ %u, MEM %p",
+               (unsigned long long)pci_resource_start(pci_dev, 1),
                irq, bus_to_virt(pci_resource_start(pci_dev, 0)));
 
        // check IO region
index f2eeaf9dc56a4fffe9dff197a5899588d02f5098..d40605c1af73819daf6095dbcd3112bd7fb1c724 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
+#include <linux/poison.h>
 #include <linux/errno.h>
 #include <linux/atm.h>
 #include <linux/atmdev.h>
@@ -754,7 +755,7 @@ static void process_txdone_queue (struct fs_dev *dev, struct queue *q)
                        fs_kfree_skb (skb);
 
                        fs_dprintk (FS_DEBUG_ALLOC, "Free trans-d: %p\n", td); 
-                       memset (td, 0x12, sizeof (struct FS_BPENTRY));
+                       memset (td, ATM_POISON_FREE, sizeof(struct FS_BPENTRY));
                        kfree (td);
                        break;
                default:
@@ -1657,9 +1658,10 @@ static int __devinit fs_init (struct fs_dev *dev)
        func_enter ();
        pci_dev = dev->pci_dev;
 
-       printk (KERN_INFO "found a FireStream %d card, base %08lx, irq%d.\n", 
+       printk (KERN_INFO "found a FireStream %d card, base %16llx, irq%d.\n",
                IS_FS50(dev)?50:155,
-               pci_resource_start(pci_dev, 0), dev->pci_dev->irq);
+               (unsigned long long)pci_resource_start(pci_dev, 0),
+               dev->pci_dev->irq);
 
        if (fs_debug & FS_DEBUG_INIT)
                my_hd ((unsigned char *) dev, sizeof (*dev));
index dd712b24ec91900f3b75506af6ecf6467f7ba160..4bef76a2f3f2a7611ff0dcbca79c8d774d7a7255 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/cpu.h>
 #include <linux/topology.h>
 #include <linux/device.h>
+#include <linux/node.h>
 
 #include "base.h"
 
@@ -57,13 +58,12 @@ static void __devinit register_cpu_control(struct cpu *cpu)
 {
        sysdev_create_file(&cpu->sysdev, &attr_online);
 }
-void unregister_cpu(struct cpu *cpu, struct node *root)
+void unregister_cpu(struct cpu *cpu)
 {
        int logical_cpu = cpu->sysdev.id;
 
-       if (root)
-               sysfs_remove_link(&root->sysdev.kobj,
-                                 kobject_name(&cpu->sysdev.kobj));
+       unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu));
+
        sysdev_remove_file(&cpu->sysdev, &attr_online);
 
        sysdev_unregister(&cpu->sysdev);
@@ -109,23 +109,21 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
  *
  * Initialize and register the CPU device.
  */
-int __devinit register_cpu(struct cpu *cpu, int num, struct node *root)
+int __devinit register_cpu(struct cpu *cpu, int num)
 {
        int error;
-
        cpu->node_id = cpu_to_node(num);
        cpu->sysdev.id = num;
        cpu->sysdev.cls = &cpu_sysdev_class;
 
        error = sysdev_register(&cpu->sysdev);
-       if (!error && root)
-               error = sysfs_create_link(&root->sysdev.kobj,
-                                         &cpu->sysdev.kobj,
-                                         kobject_name(&cpu->sysdev.kobj));
+
        if (!error && !cpu->no_control)
                register_cpu_control(cpu);
        if (!error)
                cpu_sys_devices[num] = &cpu->sysdev;
+       if (!error)
+               register_cpu_under_node(num, cpu_to_node(num));
 
 #ifdef CONFIG_KEXEC
        if (!error)
@@ -145,5 +143,13 @@ EXPORT_SYMBOL_GPL(get_cpu_sysdev);
 
 int __init cpu_dev_init(void)
 {
-       return sysdev_class_register(&cpu_sysdev_class);
+       int err;
+
+       err = sysdev_class_register(&cpu_sysdev_class);
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+       if (!err)
+               err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);
+#endif
+
+       return err;
 }
index e2f64f91ed0558fcc6b9a70feb9620170685c485..33c5cce1560b261b767fa56faa410e19ed47d5e4 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/dmapool.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/poison.h>
 
 /*
  * Pool allocator ... wraps the dma_alloc_coherent page allocator, so
@@ -35,8 +36,6 @@ struct dma_page {     /* cacheable header for 'allocation' bytes */
 };
 
 #define        POOL_TIMEOUT_JIFFIES    ((100 /* msec */ * HZ) / 1000)
-#define        POOL_POISON_FREED       0xa7    /* !inuse */
-#define        POOL_POISON_ALLOCATED   0xa9    /* !initted */
 
 static DECLARE_MUTEX (pools_lock);
 
index dd547af4681a50c87dc976cea8c22ee497f9a133..c6b7d9c4b65115054f3f9cd3591c7dbf2c75142d 100644 (file)
@@ -306,11 +306,13 @@ static ssize_t
 memory_probe_store(struct class *class, const char *buf, size_t count)
 {
        u64 phys_addr;
+       int nid;
        int ret;
 
        phys_addr = simple_strtoull(buf, NULL, 0);
 
-       ret = add_memory(phys_addr, PAGES_PER_SECTION << PAGE_SHIFT);
+       nid = memory_add_physaddr_to_nid(phys_addr);
+       ret = add_memory(nid, phys_addr, PAGES_PER_SECTION << PAGE_SHIFT);
 
        if (ret)
                count = ret;
index c80c3aeed004a558de9cf9db0632191cf1c16c99..eae2bdc183bb7741a85c23f086d156c95b1d0317 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/cpumask.h>
 #include <linux/topology.h>
 #include <linux/nodemask.h>
+#include <linux/cpu.h>
 
 static struct sysdev_class node_class = {
        set_kset_name("node"),
@@ -190,6 +191,66 @@ void unregister_node(struct node *node)
        sysdev_unregister(&node->sysdev);
 }
 
+struct node node_devices[MAX_NUMNODES];
+
+/*
+ * register cpu under node
+ */
+int register_cpu_under_node(unsigned int cpu, unsigned int nid)
+{
+       if (node_online(nid)) {
+               struct sys_device *obj = get_cpu_sysdev(cpu);
+               if (!obj)
+                       return 0;
+               return sysfs_create_link(&node_devices[nid].sysdev.kobj,
+                                        &obj->kobj,
+                                        kobject_name(&obj->kobj));
+        }
+
+       return 0;
+}
+
+int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
+{
+       if (node_online(nid)) {
+               struct sys_device *obj = get_cpu_sysdev(cpu);
+               if (obj)
+                       sysfs_remove_link(&node_devices[nid].sysdev.kobj,
+                                        kobject_name(&obj->kobj));
+       }
+       return 0;
+}
+
+int register_one_node(int nid)
+{
+       int error = 0;
+       int cpu;
+
+       if (node_online(nid)) {
+               int p_node = parent_node(nid);
+               struct node *parent = NULL;
+
+               if (p_node != nid)
+                       parent = &node_devices[p_node];
+
+               error = register_node(&node_devices[nid], nid, parent);
+
+               /* link cpu under this node */
+               for_each_present_cpu(cpu) {
+                       if (cpu_to_node(cpu) == nid)
+                               register_cpu_under_node(cpu, nid);
+               }
+       }
+
+       return error;
+
+}
+
+void unregister_one_node(int nid)
+{
+       unregister_node(&node_devices[nid]);
+}
+
 static int __init register_node_type(void)
 {
        return sysdev_class_register(&node_class);
index 8c52421cbc545b54a6ce1c84c0cf1bf3f734c751..c2d621632383306a493fd5f60d5d3b9b55721f70 100644 (file)
@@ -107,7 +107,7 @@ static int __cpuinit topology_remove_dev(struct sys_device * sys_dev)
        return 0;
 }
 
-static int topology_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
                unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
@@ -125,7 +125,7 @@ static int topology_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block topology_cpu_notifier =
+static struct notifier_block __cpuinitdata topology_cpu_notifier =
 {
        .notifier_call = topology_cpu_callback,
 };
index dd8a1501142f9a7acab30803c86d5390d666dbf4..50ca1aa4ee3b3956550f23fce6d1b098f0c86e30 100644 (file)
@@ -2530,7 +2530,6 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
        blk_queue_max_sectors(RequestQueue, Controller->MaxBlocksPerCommand);
        disk->queue = RequestQueue;
        sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n);
-       sprintf(disk->devfs_name, "rd/host%d/target%d", Controller->ControllerNumber, n);
        disk->major = MajorNumber;
        disk->first_minor = n << DAC960_MaxPartitionsBits;
        disk->fops = &DAC960_BlockDeviceOperations;
index 196c0ec9cd5421da1c1f278d15fc66e5d474b8f4..a317e43039526ab586eae5a1f2bb73a9fe31345c 100644 (file)
@@ -1732,13 +1732,10 @@ int acsi_init( void )
                struct gendisk *disk = acsi_gendisk[i];
                sprintf(disk->disk_name, "ad%c", 'a'+i);
                aip = &acsi_info[NDevices];
-               sprintf(disk->devfs_name, "ad/target%d/lun%d", aip->target, aip->lun);
                disk->major = ACSI_MAJOR;
                disk->first_minor = i << 4;
-               if (acsi_info[i].type != HARDDISK) {
+               if (acsi_info[i].type != HARDDISK)
                        disk->minors = 1;
-                       strcat(disk->devfs_name, "/disc");
-               }
                disk->fops = &acsi_fops;
                disk->private_data = &acsi_info[i];
                set_capacity(disk, acsi_info[i].size);
index 4cb9c13362874cedbed44c24a2982046d1e74e4c..4030a8fd11872992e2c5040746c873f6e8a6f01a 100644 (file)
@@ -65,7 +65,6 @@ not be guaranteed. There are several ways to assure this:
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
 
 #include <asm/pgtable.h>
@@ -1005,11 +1004,6 @@ int slm_init( void )
        BufferP = SLMBuffer;
        SLMState = IDLE;
        
-       devfs_mk_dir("slm");
-       for (i = 0; i < MAX_SLM; i++) {
-               devfs_mk_cdev(MKDEV(ACSI_MAJOR, i),
-                               S_IFCHR|S_IRUSR|S_IWUSR, "slm/%d", i);
-       }
        return 0;
 }
 
@@ -1032,10 +1026,6 @@ int init_module(void)
 
 void cleanup_module(void)
 {
-       int i;
-       for (i = 0; i < MAX_SLM; i++)
-               devfs_remove("slm/%d", i);
-       devfs_remove("slm");
        if (unregister_chrdev( ACSI_MAJOR, "slm" ) != 0)
                printk( KERN_ERR "acsi_slm: cleanup_module failed\n");
        atari_stram_free( SLMBuffer );
index 39b0f53186e8a2a6532799c6ac172c4eeab7b96e..05fb08312c01c619fbc176a5246f277d4a90b34a 100644 (file)
@@ -3248,7 +3248,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
                q->queuedata = hba[i];
                sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
-               sprintf(disk->devfs_name, "cciss/host%d/target%d", i, j);
                disk->major = hba[i]->major;
                disk->first_minor = j << NWD_SHIFT;
                disk->fops = &cciss_fops;
index 5eb6fb7b5cfacfba6c84672cd38aaf631f401c85..bfd245df0a8c5bb81a79828d38b65b153e5dd0e3 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/blkpg.h>
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
@@ -348,7 +347,6 @@ static void __devexit cpqarray_remove_one(int i)
        for(j = 0; j < NWD; j++) {
                if (ida_gendisk[i][j]->flags & GENHD_FL_UP)
                        del_gendisk(ida_gendisk[i][j]);
-               devfs_remove("ida/c%dd%d",i,j);
                put_disk(ida_gendisk[i][j]);
        }
        blk_cleanup_queue(hba[i]->queue);
@@ -1807,8 +1805,6 @@ static void getgeometry(int ctlr)
 
                                }
 
-                               sprintf(disk->devfs_name, "ida/c%dd%d", ctlr, log_unit);
-
                                info_p->phys_drives =
                                    sense_config_buf->ctlr_phys_drv;
                                info_p->drv_assign_map
@@ -1844,7 +1840,6 @@ static void __exit cpqarray_exit(void)
                }
        }
 
-       devfs_remove("ida");
        remove_proc_entry("cpqarray", proc_root_driver);
 }
 
index dff1e67b1dd4e2768447ac92465caf8e1cceb97a..0242cbb86a8793d24ac4617fc344a43f6dcf9ca4 100644 (file)
@@ -177,7 +177,6 @@ static int print_unex = 1;
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/platform_device.h>
 #include <linux/buffer_head.h> /* for invalidate_buffers() */
 #include <linux/mutex.h>
@@ -224,7 +223,6 @@ static struct completion device_release;
 static unsigned short virtual_dma_port = 0x3f0;
 irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int set_dor(int fdc, char mask, char data);
-static void register_devfs_entries(int drive) __init;
 
 #define K_64   0x10000         /* 64KB */
 
@@ -3676,7 +3674,6 @@ static void __init config_types(void)
                                first = 0;
                        }
                        printk("%s fd%d is %s", prepend, drive, name);
-                       register_devfs_entries(drive);
                }
                *UDP = *params;
        }
@@ -3954,37 +3951,6 @@ static struct block_device_operations floppy_fops = {
        .media_changed  = check_floppy_change,
        .revalidate_disk = floppy_revalidate,
 };
-static char *table[] = {
-       "", "d360", "h1200", "u360", "u720", "h360", "h720",
-       "u1440", "u2880", "CompaQ", "h1440", "u1680", "h410",
-       "u820", "h1476", "u1722", "h420", "u830", "h1494", "u1743",
-       "h880", "u1040", "u1120", "h1600", "u1760", "u1920",
-       "u3200", "u3520", "u3840", "u1840", "u800", "u1600",
-       NULL
-};
-static int t360[] = { 1, 0 },
-       t1200[] = { 2, 5, 6, 10, 12, 14, 16, 18, 20, 23, 0 },
-       t3in[] = { 8, 9, 26, 27, 28, 7, 11, 15, 19, 24, 25, 29, 31, 3, 4, 13,
-                       17, 21, 22, 30, 0 };
-static int *table_sup[] =
-    { NULL, t360, t1200, t3in + 5 + 8, t3in + 5, t3in, t3in };
-
-static void __init register_devfs_entries(int drive)
-{
-       int base_minor = (drive < 4) ? drive : (124 + drive);
-
-       if (UDP->cmos < ARRAY_SIZE(default_drive_params)) {
-               int i = 0;
-               do {
-                       int minor = base_minor + (table_sup[UDP->cmos][i] << 2);
-
-                       devfs_mk_bdev(MKDEV(FLOPPY_MAJOR, minor),
-                                     S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |
-                                     S_IWGRP, "floppy/%d%s", drive,
-                                     table[table_sup[UDP->cmos][i]]);
-               } while (table_sup[UDP->cmos][i++]);
-       }
-}
 
 /*
  * Floppy Driver initialization
@@ -4261,11 +4227,9 @@ static int __init floppy_init(void)
                motor_off_timer[dr].function = motor_off_callback;
        }
 
-       devfs_mk_dir("floppy");
-
        err = register_blkdev(FLOPPY_MAJOR, "fd");
        if (err)
-               goto out_devfs_remove;
+               goto out_put_disk;
 
        floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
        if (!floppy_queue) {
@@ -4424,8 +4388,6 @@ out_unreg_region:
        blk_cleanup_queue(floppy_queue);
 out_unreg_blkdev:
        unregister_blkdev(FLOPPY_MAJOR, "fd");
-out_devfs_remove:
-       devfs_remove("floppy");
 out_put_disk:
        while (dr--) {
                del_timer(&motor_off_timer[dr]);
@@ -4586,19 +4548,6 @@ static void floppy_release_irq_and_dma(void)
 
 static char *floppy;
 
-static void unregister_devfs_entries(int drive)
-{
-       int i;
-
-       if (UDP->cmos < ARRAY_SIZE(default_drive_params)) {
-               i = 0;
-               do {
-                       devfs_remove("floppy/%d%s", drive,
-                                    table[table_sup[UDP->cmos][i]]);
-               } while (table_sup[UDP->cmos][i++]);
-       }
-}
-
 static void __init parse_floppy_cfg_string(char *cfg)
 {
        char *ptr;
@@ -4635,13 +4584,11 @@ void cleanup_module(void)
                if ((allowed_drive_mask & (1 << drive)) &&
                    fdc_state[FDC(drive)].version != FDC_NONE) {
                        del_gendisk(disks[drive]);
-                       unregister_devfs_entries(drive);
                        device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
                        platform_device_unregister(&floppy_device[drive]);
                }
                put_disk(disks[drive]);
        }
-       devfs_remove("floppy");
 
        del_timer_sync(&fd_timeout);
        del_timer_sync(&fd_timer);
index 3c74ea729fc79529ed766b98f3e1d2b78bb3da57..013c5daddb0b3bfc1163506a0be14961c9ac32e1 100644 (file)
@@ -63,7 +63,6 @@
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
 #include <linux/swap.h>
 #include <linux/slab.h>
@@ -210,7 +209,7 @@ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
 {
        struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
        struct address_space *mapping = file->f_mapping;
-       struct address_space_operations *aops = mapping->a_ops;
+       const struct address_space_operations *aops = mapping->a_ops;
        pgoff_t index;
        unsigned offset, bv_offs;
        int len, ret;
@@ -784,7 +783,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
 
        error = -EINVAL;
        if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) {
-               struct address_space_operations *aops = mapping->a_ops;
+               const struct address_space_operations *aops = mapping->a_ops;
                /*
                 * If we can't read - sorry. If we only can't write - well,
                 * it's going to be read-only.
@@ -1277,8 +1276,6 @@ static int __init loop_init(void)
                        goto out_mem3;
        }
 
-       devfs_mk_dir("loop");
-
        for (i = 0; i < max_loop; i++) {
                struct loop_device *lo = &loop_dev[i];
                struct gendisk *disk = disks[i];
@@ -1296,7 +1293,6 @@ static int __init loop_init(void)
                disk->first_minor = i;
                disk->fops = &lo_fops;
                sprintf(disk->disk_name, "loop%d", i);
-               sprintf(disk->devfs_name, "loop/%d", i);
                disk->private_data = lo;
                disk->queue = lo->lo_queue;
        }
@@ -1310,7 +1306,6 @@ static int __init loop_init(void)
 out_mem4:
        while (i--)
                blk_cleanup_queue(loop_dev[i].lo_queue);
-       devfs_remove("loop");
        i = max_loop;
 out_mem3:
        while (i--)
@@ -1333,7 +1328,6 @@ static void loop_exit(void)
                blk_cleanup_queue(loop_dev[i].lo_queue);
                put_disk(disks[i]);
        }
-       devfs_remove("loop");
        if (unregister_blkdev(LOOP_MAJOR, "loop"))
                printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 
index 7f554f2ed0797af3b39d87d4354609169203fdb0..39662f0c9cce65afd9da3b397607093f05a3f026 100644 (file)
@@ -29,8 +29,6 @@
 #include <linux/kernel.h>
 #include <net/sock.h>
 
-#include <linux/devfs_fs_kernel.h>
-
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/types.h>
@@ -642,7 +640,6 @@ static int __init nbd_init(void)
        printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR);
        dprintk(DBG_INIT, "nbd: debugflags=0x%x\n", debugflags);
 
-       devfs_mk_dir("nbd");
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = nbd_dev[i].disk;
                nbd_dev[i].file = NULL;
@@ -660,7 +657,6 @@ static int __init nbd_init(void)
                disk->private_data = &nbd_dev[i];
                disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
                sprintf(disk->disk_name, "nbd%d", i);
-               sprintf(disk->devfs_name, "nbd/%d", i);
                set_capacity(disk, 0x7ffffc00ULL << 1); /* 2 TB */
                add_disk(disk);
        }
@@ -686,7 +682,6 @@ static void __exit nbd_cleanup(void)
                        put_disk(disk);
                }
        }
-       devfs_remove("nbd");
        unregister_blkdev(NBD_MAJOR, "nbd");
        printk(KERN_INFO "nbd: unregistered device at major %d\n", NBD_MAJOR);
 }
index 852b564e903a69566a1f3b82d3a339d884db9b98..1a9dee19efcf11cfc61d02dc383a4cb04ff222d9 100644 (file)
@@ -707,7 +707,7 @@ static int pf_detect(void)
                        if (pi_init(pf->pi, 0, conf[D_PRT], conf[D_MOD],
                                    conf[D_UNI], conf[D_PRO], conf[D_DLY],
                                    pf_scratch, PI_PF, verbose, pf->name)) {
-                               if (!pf_probe(pf) && pf->disk) {
+                               if (pf->disk && !pf_probe(pf)) {
                                        pf->present = 1;
                                        k++;
                                } else
index 79b868254032a68505abb3140b8918f8395ee4e2..13f998aa1cd3ffc19ccf402fd901b91e8b0dbf2d 100644 (file)
@@ -156,7 +156,6 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/mtio.h>
@@ -674,25 +673,15 @@ static int __init pg_init(void)
                err = PTR_ERR(pg_class);
                goto out_chrdev;
        }
-       devfs_mk_dir("pg");
        for (unit = 0; unit < PG_UNITS; unit++) {
                struct pg *dev = &devices[unit];
-               if (dev->present) {
+               if (dev->present)
                        class_device_create(pg_class, NULL, MKDEV(major, unit),
                                        NULL, "pg%u", unit);
-                       err = devfs_mk_cdev(MKDEV(major, unit),
-                                     S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u",
-                                     unit);
-                       if (err) 
-                               goto out_class;
-               }
        }
        err = 0;
        goto out;
 
-out_class:
-       class_device_destroy(pg_class, MKDEV(major, unit));
-       class_destroy(pg_class);
 out_chrdev:
        unregister_chrdev(major, "pg");
 out:
@@ -705,13 +694,10 @@ static void __exit pg_exit(void)
 
        for (unit = 0; unit < PG_UNITS; unit++) {
                struct pg *dev = &devices[unit];
-               if (dev->present) {
+               if (dev->present)
                        class_device_destroy(pg_class, MKDEV(major, unit));
-                       devfs_remove("pg/%u", unit);
-               }
        }
        class_destroy(pg_class);
-       devfs_remove("pg");
        unregister_chrdev(major, name);
 
        for (unit = 0; unit < PG_UNITS; unit++) {
index d2013d362403819c49c2e21ffe54f64f311796cd..35fb2663672146d0cdbd1ed15ea36da68d1bb223 100644 (file)
@@ -141,7 +141,6 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/mtio.h>
@@ -971,32 +970,15 @@ static int __init pt_init(void)
                goto out_chrdev;
        }
 
-       devfs_mk_dir("pt");
        for (unit = 0; unit < PT_UNITS; unit++)
                if (pt[unit].present) {
                        class_device_create(pt_class, NULL, MKDEV(major, unit),
                                        NULL, "pt%d", unit);
-                       err = devfs_mk_cdev(MKDEV(major, unit),
-                                     S_IFCHR | S_IRUSR | S_IWUSR,
-                                     "pt/%d", unit);
-                       if (err) {
-                               class_device_destroy(pt_class, MKDEV(major, unit));
-                               goto out_class;
-                       }
                        class_device_create(pt_class, NULL, MKDEV(major, unit + 128),
                                        NULL, "pt%dn", unit);
-                       err = devfs_mk_cdev(MKDEV(major, unit + 128),
-                                     S_IFCHR | S_IRUSR | S_IWUSR,
-                                     "pt/%dn", unit);
-                       if (err) {
-                               class_device_destroy(pt_class, MKDEV(major, unit + 128));
-                               goto out_class;
-                       }
                }
        goto out;
 
-out_class:
-       class_destroy(pt_class);
 out_chrdev:
        unregister_chrdev(major, "pt");
 out:
@@ -1009,12 +991,9 @@ static void __exit pt_exit(void)
        for (unit = 0; unit < PT_UNITS; unit++)
                if (pt[unit].present) {
                        class_device_destroy(pt_class, MKDEV(major, unit));
-                       devfs_remove("pt/%d", unit);
                        class_device_destroy(pt_class, MKDEV(major, unit + 128));
-                       devfs_remove("pt/%dn", unit);
                }
        class_destroy(pt_class);
-       devfs_remove("pt");
        unregister_chrdev(major, name);
        for (unit = 0; unit < PT_UNITS; unit++)
                if (pt[unit].present)
index a04f60693c396446d4a310e8c1df0eaef62c5012..3e4cce5e4736351befab56db81c42527223dade8 100644 (file)
@@ -2612,7 +2612,6 @@ static struct file_operations pkt_ctl_fops = {
 static struct miscdevice pkt_misc = {
        .minor          = MISC_DYNAMIC_MINOR,
        .name           = "pktcdvd",
-       .devfs_name     = "pktcdvd/control",
        .fops           = &pkt_ctl_fops
 };
 
index bea75f2cb211ca342814766f963b546071c8b223..a729013a39737b24541a999f38950c7206ae6181 100644 (file)
@@ -421,7 +421,6 @@ static int __init ps2esdi_geninit(void)
                disk->major = PS2ESDI_MAJOR;
                disk->first_minor = i<<6;
                sprintf(disk->disk_name, "ed%c", 'a'+i);
-               sprintf(disk->devfs_name, "ed/target%d", i);
                disk->fops = &ps2esdi_fops;
                ps2esdi_gendisk[i] = disk;
        }
index 940bfd7951e5c1c582a672447b65dd28ff1367c7..a9e1c2524c2a9c99b93b36c544e716eb299cdc7f 100644 (file)
@@ -50,7 +50,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/pagemap.h>
 #include <linux/blkdev.h>
 #include <linux/genhd.h>
@@ -191,7 +190,7 @@ static int ramdisk_set_page_dirty(struct page *page)
        return 0;
 }
 
-static struct address_space_operations ramdisk_aops = {
+static const struct address_space_operations ramdisk_aops = {
        .readpage       = ramdisk_readpage,
        .prepare_write  = ramdisk_prepare_write,
        .commit_write   = ramdisk_commit_write,
@@ -412,7 +411,6 @@ static void __exit rd_cleanup(void)
                put_disk(rd_disks[i]);
                blk_cleanup_queue(rd_queue[i]);
        }
-       devfs_remove("rd");
        unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
 }
 
@@ -442,8 +440,6 @@ static int __init rd_init(void)
                goto out;
        }
 
-       devfs_mk_dir("rd");
-
        for (i = 0; i < CONFIG_BLK_DEV_RAM_COUNT; i++) {
                struct gendisk *disk = rd_disks[i];
 
@@ -461,7 +457,6 @@ static int __init rd_init(void)
                disk->queue = rd_queue[i];
                disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
                sprintf(disk->disk_name, "ram%d", i);
-               sprintf(disk->devfs_name, "rd/%d", i);
                set_capacity(disk, rd_size * 2);
                add_disk(rd_disks[i]);
        }
index 01f042f6f1c42874e9090ce60f0e925d7b73726c..628877945f9badbae4f529f63e2add13292d35cf 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/fd.h>
 #include <linux/ioctl.h>
 #include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
@@ -1019,8 +1018,6 @@ int swim3_init(void)
        int err = -ENOMEM;
        int i;
 
-       devfs_mk_dir("floppy");
-
        swim = find_devices("floppy");
        while (swim && (floppy_count < MAX_FLOPPIES))
        {
@@ -1064,7 +1061,6 @@ int swim3_init(void)
                disk->queue = swim3_queue;
                disk->flags |= GENHD_FL_REMOVABLE;
                sprintf(disk->disk_name, "fd%d", i);
-               sprintf(disk->devfs_name, "floppy/%d", i);
                set_capacity(disk, 2880);
                add_disk(disk);
        }
index 2ae08b343b935518c86098959866299e73f213e8..10a4aa5fb54df10d0f48b710a02bd12a26d382f5 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/spinlock.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/interrupt.h>
 #include <linux/compiler.h>
 #include <linux/workqueue.h>
@@ -1510,7 +1509,6 @@ static int carm_init_disks(struct carm_host *host)
                port->disk = disk;
                sprintf(disk->disk_name, DRV_NAME "/%u",
                        (unsigned int) (host->id * CARM_MAX_PORTS) + i);
-               sprintf(disk->devfs_name, DRV_NAME "/%u_%u", host->id, i);
                disk->major = host->major;
                disk->first_minor = i * CARM_MINORS_PER_MAJOR;
                disk->fops = &carm_bd_ops;
@@ -1672,8 +1670,6 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (host->flags & FL_DYN_MAJOR)
                host->major = rc;
 
-       devfs_mk_dir(DRV_NAME);
-
        rc = carm_init_disks(host);
        if (rc)
                goto err_out_blkdev_disks;
@@ -1694,9 +1690,10 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        DPRINTK("waiting for probe_comp\n");
        wait_for_completion(&host->probe_comp);
 
-       printk(KERN_INFO "%s: pci %s, ports %d, io %lx, irq %u, major %d\n",
+       printk(KERN_INFO "%s: pci %s, ports %d, io %llx, irq %u, major %d\n",
               host->name, pci_name(pdev), (int) CARM_MAX_PORTS,
-              pci_resource_start(pdev, 0), pdev->irq, host->major);
+              (unsigned long long)pci_resource_start(pdev, 0),
+                  pdev->irq, host->major);
 
        carm_host_id++;
        pci_set_drvdata(pdev, host);
@@ -1738,7 +1735,6 @@ static void carm_remove_one (struct pci_dev *pdev)
 
        free_irq(pdev->irq, host);
        carm_free_disks(host);
-       devfs_remove(DRV_NAME);
        unregister_blkdev(host->major, host->name);
        if (host->major == 160)
                clear_bit(0, &carm_major_alloc);
index 60e9a9457c6b0789b7b29e0e8c36e148b9424653..d62b49fbf10c319334ca6f26e49f58a46747b6f3 100644 (file)
 #include <linux/usb.h>
 #include <linux/usb_usual.h>
 #include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/timer.h>
 #include <scsi/scsi.h>
 
 #define DRV_NAME "ub"
-#define DEVFS_NAME DRV_NAME
 
 #define UB_MAJOR 180
 
@@ -2291,7 +2289,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
                goto err_diskalloc;
 
        sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
-       sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a');
        disk->major = UB_MAJOR;
        disk->first_minor = lun->id * UB_PARTS_PER_LUN;
        disk->fops = &ub_bd_fops;
@@ -2445,7 +2442,6 @@ static int __init ub_init(void)
 
        if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
                goto err_regblkdev;
-       devfs_mk_dir(DEVFS_NAME);
 
        if ((rc = usb_register(&ub_driver)) != 0)
                goto err_register;
@@ -2454,7 +2450,6 @@ static int __init ub_init(void)
        return 0;
 
 err_register:
-       devfs_remove(DEVFS_NAME);
        unregister_blkdev(UB_MAJOR, DRV_NAME);
 err_regblkdev:
        return rc;
@@ -2464,7 +2459,6 @@ static void __exit ub_exit(void)
 {
        usb_deregister(&ub_driver);
 
-       devfs_remove(DEVFS_NAME);
        unregister_blkdev(UB_MAJOR, DRV_NAME);
        usb_usual_clear_present(USB_US_TYPE_UB);
 }
index f7d4c65a7b8c369a76c3b7b82d8cb98ce03dcfa0..585197b95af762118d5692b0d5303b713f95f472 100644 (file)
@@ -1192,7 +1192,6 @@ static int __init mm_init(void)
        for (i = 0; i < num_cards; i++) {
                struct gendisk *disk = mm_gendisk[i];
                sprintf(disk->disk_name, "umem%c", 'a'+i);
-               sprintf(disk->devfs_name, "umem/card%d", i);
                spin_lock_init(&cards[i].lock);
                disk->major = major_nr;
                disk->first_minor  = i << MM_SHIFT;
index b0df4f5ab97afff4d490e9781fae37bd9984a210..ec5a1b90a0a24133d1043fb19290a1d296b11125 100644 (file)
@@ -59,7 +59,6 @@ MODULE_LICENSE("GPL");
  * numbers 0-255 we get a maximum of 32 disks.
  */
 #define VIOD_GENHD_NAME                "iseries/vd"
-#define VIOD_GENHD_DEVFS_NAME  "iseries/disc"
 
 #define VIOD_VERS              "1.64"
 
@@ -523,8 +522,6 @@ retry:
        else
                snprintf(g->disk_name, sizeof(g->disk_name),
                                VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26));
-       snprintf(g->devfs_name, sizeof(g->devfs_name),
-                       "%s%d", VIOD_GENHD_DEVFS_NAME, dev_no);
        g->fops = &viodasd_fops;
        g->queue = q;
        g->private_data = d;
index cbce7c5e9445638474640e59738db7b7cec3b74b..e828e4cbd3e1122a0ca3abb48e7ed2de51a6bf81 100644 (file)
@@ -215,7 +215,6 @@ static int __init xd_init(void)
                disk->major = XT_DISK_MAJOR;
                disk->first_minor = i<<6;
                sprintf(disk->disk_name, "xd%c", i+'a');
-               sprintf(disk->devfs_name, "xd/target%d", i);
                disk->fops = &xd_fops;
                disk->private_data = p;
                disk->queue = xd_queue;
index bb5e8d665a2a3ce8bd41fbd647bd06eeec772541..82ddbdd7bd4ba18f0718e388f6db83b8131992a9 100644 (file)
@@ -354,7 +354,6 @@ z2_init(void)
     z2ram_gendisk->first_minor = 0;
     z2ram_gendisk->fops = &z2_fops;
     sprintf(z2ram_gendisk->disk_name, "z2ram");
-    strcpy(z2ram_gendisk->devfs_name, z2ram_gendisk->disk_name);
 
     z2ram_gendisk->queue = z2_queue;
     add_disk(z2ram_gendisk);
index ec004897b63494e220f87a211056903731a5b122..ec469497c10ff46abbb5818d8ea8726284f05d4a 100644 (file)
@@ -1918,7 +1918,6 @@ static int __init aztcd_init(void)
        azt_disk->first_minor = 0;
        azt_disk->fops = &azt_fops;
        sprintf(azt_disk->disk_name, "aztcd");
-       sprintf(azt_disk->devfs_name, "aztcd");
        azt_disk->queue = azt_queue;
        add_disk(azt_disk);
        azt_invalidate_buffers();
index 72ffd64e8b1e8c43ad7a3bc39fc05fbf5b3d5978..5f0f2027f29e46ebb6593662423b4f8522792dfd 100644 (file)
 #include <linux/hdreg.h>
 #include <linux/genhd.h>
 #include <linux/ioport.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/init.h>
index f43a988dd413e0cc9fbdbf2db9e9fef04f2c948d..4ee288688fed492378f87fb2f10c1fdcf587fe7d 100644 (file)
@@ -187,7 +187,6 @@ History:
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/cdrom.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
index ad5464ab99bce830fc22984ff1cf77ac176c51d2..b6ee50a2916d79b6a8c9c4e9f46b6ef6443f035d 100644 (file)
@@ -955,7 +955,6 @@ static int __init gscd_init(void)
        gscd_disk->first_minor = 0;
        gscd_disk->fops = &gscd_fops;
        sprintf(gscd_disk->disk_name, "gscd");
-       sprintf(gscd_disk->devfs_name, "gscd");
 
        if (register_blkdev(MAJOR_NR, "gscd")) {
                ret = -EIO;
index 0f6e7aab8d2cb18cc294b08919d87752fcf3444d..788c7a0b2fe301600f4a5c6106e12fdb95592007 100644 (file)
@@ -74,7 +74,6 @@ static const char *mcdx_c_version
 #include <linux/major.h>
 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
 #include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
 
 #include "mcdx.h"
 
index 0b0eab4f40fa989dd9c215b089282bc8d8fa106a..25032d7edc55e19a3f63a8e3dfd92a70ddca767c 100644 (file)
@@ -2033,7 +2033,6 @@ static int __init optcd_init(void)
        optcd_disk->first_minor = 0;
        optcd_disk->fops = &opt_fops;
        sprintf(optcd_disk->disk_name, "optcd");
-       sprintf(optcd_disk->devfs_name, "optcd");
 
        if (!request_region(optcd_port, 4, "optcd")) {
                printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
index 05c9e865ecaf85a33eafa3be2cfe0bb837a71148..2fc966c65a0e4458293150c62cba30eda352e659 100644 (file)
 #include <linux/kernel.h>
 #include <linux/cdrom.h>
 #include <linux/ioport.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
@@ -5808,8 +5807,6 @@ int __init sbpcd_init(void)
                return -ENOMEM;
        }
 
-       devfs_mk_dir("sbp");
-
        for (j=0;j<NR_SBPCD;j++)
        {
                struct cdrom_device_info * sbpcd_infop;
@@ -5871,7 +5868,6 @@ int __init sbpcd_init(void)
                disk->fops = &sbpcd_bdops;
                strcpy(disk->disk_name, sbpcd_infop->name);
                disk->flags = GENHD_FL_CD;
-               sprintf(disk->devfs_name, "sbp/c0t%d", p->drv_id);
                p->disk = disk;
                if (register_cdrom(sbpcd_infop))
                {
@@ -5906,7 +5902,6 @@ static void sbpcd_exit(void)
                if (D_S[j].drv_id==-1) continue;
                del_gendisk(D_S[j].disk);
                put_disk(D_S[j].disk);
-               devfs_remove("sbp/c0t%d", j);
                vfree(D_S[j].sbp_buf);
                if (D_S[j].sbp_audsiz>0)
                        vfree(D_S[j].aud_buf);
@@ -5917,7 +5912,6 @@ static void sbpcd_exit(void)
                }
                vfree(D_S[j].sbpcd_infop);
        }
-       devfs_remove("sbp");
        msg(DBG_INF, "%s module released.\n", major_name);
 }
 
index 74b1cadbf161d2adc2f7d61933622bfb8f75bc5e..bf5aef4e555b2d71696e8540a3840bb1258d5f27 100644 (file)
@@ -1695,7 +1695,6 @@ static int __init sjcd_init(void)
        sjcd_disk->first_minor = 0,
        sjcd_disk->fops = &sjcd_fops,
        sprintf(sjcd_disk->disk_name, "sjcd");
-       sprintf(sjcd_disk->devfs_name, "sjcd");
 
        if (!request_region(sjcd_base, 4,"sjcd")) {
                printk
index e6565992643260580cbbcaf7e5209a1744fd97f2..8f7cc452af8da7143a7e77280ba639f909ea1857 100644 (file)
@@ -1589,7 +1589,6 @@ static int __init sony535_init(void)
        cdu_disk->first_minor = 0;
        cdu_disk->fops = &cdu_fops;
        sprintf(cdu_disk->disk_name, "cdu");
-       sprintf(cdu_disk->devfs_name, "cdu535");
 
        if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) {
                printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n",
index af6b3bfd169ba1ccb7dc8f77c44bafad408f7dd0..54ca931e19ea0a0c0b36bc896432278dc1361812 100644 (file)
@@ -49,7 +49,6 @@
 #include <asm/iseries/vio.h>
 
 #define VIOCD_DEVICE                   "iseries/vcd"
-#define VIOCD_DEVICE_DEVFS             "iseries/vcd"
 
 #define VIOCD_VERS "1.06"
 
@@ -688,8 +687,6 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        gendisk->first_minor = deviceno;
        strncpy(gendisk->disk_name, c->name,
                        sizeof(gendisk->disk_name));
-       snprintf(gendisk->devfs_name, sizeof(gendisk->devfs_name),
-                       VIOCD_DEVICE_DEVFS "%d", deviceno);
        blk_queue_max_hw_segments(q, 1);
        blk_queue_max_phys_segments(q, 1);
        blk_queue_max_sectors(q, 4096 / 512);
index 3610c57295533c81807bbddfd174ab1ede354551..c40e487d9f5cd8a35475e4357800968eca3ba838 100644 (file)
@@ -939,12 +939,36 @@ config MWAVE
 config SCx200_GPIO
        tristate "NatSemi SCx200 GPIO Support"
        depends on SCx200
+       select NSC_GPIO
        help
          Give userspace access to the GPIO pins on the National
          Semiconductor SCx200 processors.
 
          If compiled as a module, it will be called scx200_gpio.
 
+config PC8736x_GPIO
+       tristate "NatSemi PC8736x GPIO Support"
+       depends on X86
+       default SCx200_GPIO     # mostly N
+       select NSC_GPIO         # needed for support routines
+       help
+         Give userspace access to the GPIO pins on the National
+         Semiconductor PC-8736x (x=[03456]) SuperIO chip.  The chip
+         has multiple functional units, inc several managed by
+         hwmon/pc87360 driver.  Tested with PC-87366
+
+         If compiled as a module, it will be called pc8736x_gpio.
+
+config NSC_GPIO
+       tristate "NatSemi Base GPIO Support"
+       depends on X86_32
+       # selected by SCx200_GPIO and PC8736x_GPIO
+       # what about 2 selectors differing: m != y
+       help
+         Common support used (and needed) by scx200_gpio and
+         pc8736x_gpio drivers.  If those drivers are built as
+         modules, this one will be too, named nsc_gpio
+
 config CS5535_GPIO
        tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)"
        depends on X86_32
index 524105597ea7d7ff82339902afc0c15cda691447..6e0f4469d8bbdbf37197a7e722131acf48378bf7 100644 (file)
@@ -82,6 +82,8 @@ obj-$(CONFIG_PPDEV)           += ppdev.o
 obj-$(CONFIG_NWBUTTON)         += nwbutton.o
 obj-$(CONFIG_NWFLASH)          += nwflash.o
 obj-$(CONFIG_SCx200_GPIO)      += scx200_gpio.o
+obj-$(CONFIG_PC8736x_GPIO)     += pc8736x_gpio.o
+obj-$(CONFIG_NSC_GPIO)         += nsc_gpio.o
 obj-$(CONFIG_CS5535_GPIO)      += cs5535_gpio.o
 obj-$(CONFIG_GPIO_VR41XX)      += vr41xx_giu.o
 obj-$(CONFIG_TANBAC_TB0219)    += tb0219.o
index 9826a399fa02b053c2bf9568a5192e510bb873f3..22f8cf218cc6443a1af9f523ae49dfc47fe56340 100644 (file)
@@ -1,6 +1,7 @@
 config AGP
        tristate "/dev/agpgart (AGP Support)"
        depends on ALPHA || IA64 || PPC || X86
+       depends on PCI
        ---help---
          AGP (Accelerated Graphics Port) is a bus system mainly used to
          connect graphics cards to the rest of the system.
index f690ee8cb7324fbf195946def5d05b7ef63f7f7c..f74eeeb8e37709167933ac53c3b7e23c41f2488f 100644 (file)
@@ -734,7 +734,7 @@ int __init agp_amd64_init(void)
 
        if (agp_off)
                return -EINVAL;
-       if (pci_register_driver(&agp_amd64_pci_driver) > 0) {
+       if (pci_register_driver(&agp_amd64_pci_driver) < 0) {
                struct pci_dev *dev;
                if (!agp_try_unsupported && !agp_try_unsupported_boot) {
                        printk(KERN_INFO PFX "No supported AGP bridge found.\n");
index 160564345993df646b5e803fcf804089b36614d2..f244c6682738a70842147beab1ac42b96f82fbf4 100644 (file)
@@ -41,7 +41,6 @@ static struct gatt_mask ati_generic_masks[] =
 };
 
 
-
 typedef struct _ati_page_map {
        unsigned long *real;
        unsigned long __iomem *remapped;
@@ -141,7 +140,8 @@ static int ati_create_gatt_pages(int nr_tables)
        ati_generic_private.num_tables = nr_tables;
        ati_generic_private.gatt_pages = tables;
 
-       if (retval != 0) ati_free_gatt_pages();
+       if (retval != 0)
+               ati_free_gatt_pages();
 
        return retval;
 }
@@ -219,16 +219,16 @@ static int ati_configure(void)
        ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
 
        if (is_r200())
-               pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000);
+               pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000);
        else
                pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000);
 
        /* address to map too */
-        /*
+       /*
        pci_read_config_dword(agp_bridge.dev, AGP_APBASE, &temp);
        agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
        printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr);
-        */
+       */
        writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID);
        readl(ati_generic_private.registers+ATI_GART_FEATURE_ID);       /* PCI Posting.*/
 
@@ -245,18 +245,20 @@ static int ati_configure(void)
 
 
 #ifdef CONFIG_PM
-static int agp_ati_resume(struct pci_dev *dev)
+static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state)
 {
-       pci_restore_state(dev);
+       pci_save_state(dev);
+       pci_set_power_state(dev, 3);
 
-       return ati_configure();
+       return 0;
 }
 
-static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state)
+static int agp_ati_resume(struct pci_dev *dev)
 {
-       pci_save_state(dev);
+       pci_set_power_state(dev, 0);
+       pci_restore_state(dev);
 
-       return 0;
+       return ati_configure();
 }
 #endif
 
@@ -321,9 +323,9 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start,
        unsigned long __iomem *cur_gatt;
        unsigned long addr;
 
-       if (type != 0 || mem->type != 0) {
+       if (type != 0 || mem->type != 0)
                return -EINVAL;
-       }
+
        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
                addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
                cur_gatt = GET_GATT(addr);
@@ -502,9 +504,8 @@ found:
 
        bridge->dev = pdev;
        bridge->capndx = cap_ptr;
-       
-       bridge->driver = &ati_generic_bridge;
 
+       bridge->driver = &ati_generic_bridge;
 
        printk(KERN_INFO PFX "Detected Ati %s chipset\n",
                        devs[j].chipset_name);
@@ -546,8 +547,8 @@ static struct pci_driver agp_ati_pci_driver = {
        .probe          = agp_ati_probe,
        .remove         = agp_ati_remove,
 #ifdef CONFIG_PM
-       .resume         = agp_ati_resume,
        .suspend        = agp_ati_suspend,
+       .resume         = agp_ati_resume,
 #endif
 };
 
index 4c67135c12d853052b389657d1fba450e1c3dfe4..df7f37b2739abe007a9f9f629f301941f65cadf7 100644 (file)
@@ -376,6 +376,29 @@ static void __devexit agp_nvidia_remove(struct pci_dev *pdev)
        agp_put_bridge(bridge);
 }
 
+#ifdef CONFIG_PM
+static int agp_nvidia_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       pci_save_state (pdev);
+       pci_set_power_state (pdev, 3);
+
+       return 0;
+}
+
+static int agp_nvidia_resume(struct pci_dev *pdev)
+{
+       /* set power state 0 and restore PCI space */
+       pci_set_power_state (pdev, 0);
+       pci_restore_state(pdev);
+
+       /* reconfigure AGP hardware again */
+       nvidia_configure();
+
+       return 0;
+}
+#endif
+
+
 static struct pci_device_id agp_nvidia_pci_table[] = {
        {
        .class          = (PCI_CLASS_BRIDGE_HOST << 8),
@@ -403,6 +426,10 @@ static struct pci_driver agp_nvidia_pci_driver = {
        .id_table       = agp_nvidia_pci_table,
        .probe          = agp_nvidia_probe,
        .remove         = agp_nvidia_remove,
+#ifdef CONFIG_PM
+       .suspend        = agp_nvidia_suspend,
+       .resume         = agp_nvidia_resume,
+#endif
 };
 
 static int __init agp_nvidia_init(void)
index cfa7922cb431f500788b6d0ba6360312137eee03..d73be4c2db8a9c5c6fffe250d36e2e3593ac53f5 100644 (file)
@@ -329,9 +329,8 @@ static int __devinit agp_sgi_init(void)
 
 static void __devexit agp_sgi_cleanup(void)
 {
-       if (sgi_tioca_agp_bridges)
-               kfree(sgi_tioca_agp_bridges);
-       sgi_tioca_agp_bridges=NULL;
+       kfree(sgi_tioca_agp_bridges);
+       sgi_tioca_agp_bridges = NULL;
 }
 
 module_init(agp_sgi_init);
index 9275d5e52e6de63d86309c82096f19ac5776592e..72fb60765c45a4f973c77ae67c916e85aff80485 100644 (file)
@@ -209,13 +209,16 @@ static int __init applicom_init(void)
                RamIO = ioremap(dev->resource[0].start, LEN_RAM_IO);
 
                if (!RamIO) {
-                       printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", dev->resource[0].start);
+                       printk(KERN_INFO "ac.o: Failed to ioremap PCI memory "
+                               "space at 0x%llx\n",
+                               (unsigned long long)dev->resource[0].start);
                        pci_disable_device(dev);
                        return -EIO;
                }
 
-               printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n",
-                      applicom_pci_devnames[dev->device-1], dev->resource[0].start, 
+               printk(KERN_INFO "Applicom %s found at mem 0x%llx, irq %d\n",
+                      applicom_pci_devnames[dev->device-1],
+                          (unsigned long long)dev->resource[0].start,
                       dev->irq);
 
                boardno = ac_register_board(dev->resource[0].start, RamIO,0);
index 122e7a72a4e178755dedce7922ff91b2f29a2f3e..2657eeba7da63aec1bce32abe8e45a5a4fcb89a0 100644 (file)
@@ -5250,7 +5250,6 @@ cy_init(void)
     cy_serial_driver->owner = THIS_MODULE;
     cy_serial_driver->driver_name = "cyclades";
     cy_serial_driver->name = "ttyC";
-    cy_serial_driver->devfs_name = "tts/C";
     cy_serial_driver->major = CYCLADES_MAJOR;
     cy_serial_driver->minor_start = 0;
     cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
index 6543b9a14c42e677038bd001309e35143c5a10a1..d117cc9971922f5ec8a6c713da435221c4eb2af7 100644 (file)
@@ -43,7 +43,7 @@ typedef struct drm_mem_stats {
        unsigned long bytes_freed;
 } drm_mem_stats_t;
 
-static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(drm_mem_lock);
 static unsigned long drm_ram_available = 0;    /* In pages */
 static unsigned long drm_ram_used = 0;
 static drm_mem_stats_t drm_mem_stats[] =
index b7f17457b4243bb1c18e8dea11b6b7149a22e7fe..78a81a4a99c5c60fda46b05497351e211d94df1f 100644 (file)
@@ -557,7 +557,7 @@ via_init_dmablit(drm_device_t *dev)
                blitq->num_outstanding = 0;
                blitq->is_active = 0;
                blitq->aborting = 0;
-               blitq->blit_lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&blitq->blit_lock);
                for (j=0; j<VIA_NUM_BLIT_SLOTS; ++j) {
                        DRM_INIT_WAITQUEUE(blitq->blit_queue + j);
                }
index e233cf280bc024498c3fdd637d219e8159bb6f2a..09b413618b5781e8c8294e66396361ab5e6354df 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
 #include <linux/device.h>
 
@@ -518,17 +517,9 @@ static int __init dsp56k_init_driver(void)
        }
        class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
 
-       err = devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0),
-                     S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k");
-       if(err)
-               goto out_class;
-
        printk(banner);
        goto out;
 
-out_class:
-       class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
-       class_destroy(dsp56k_class);
 out_chrdev:
        unregister_chrdev(DSP56K_MAJOR, "dsp56k");
 out:
@@ -541,7 +532,6 @@ static void __exit dsp56k_cleanup_driver(void)
        class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
        class_destroy(dsp56k_class);
        unregister_chrdev(DSP56K_MAJOR, "dsp56k");
-       devfs_remove("dsp56k");
 }
 module_exit(dsp56k_cleanup_driver);
 
index 87dcaa237f0753eb3e9f821bf17bb27b211b729d..da2c89f1b8bc9e15399e37a56a091ad9ea0870ff 100644 (file)
@@ -62,7 +62,6 @@
 #include <linux/init.h>                /* for __init, module_{init,exit} */
 #include <linux/poll.h>                /* for POLLIN, etc. */
 #include <linux/dtlk.h>                /* local header file for DoubleTalk values */
-#include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
 
 #ifdef TRACING
@@ -337,9 +336,6 @@ static int __init dtlk_init(void)
        if (dtlk_dev_probe() == 0)
                printk(", MAJOR %d\n", dtlk_major);
 
-       devfs_mk_cdev(MKDEV(dtlk_major, DTLK_MINOR),
-                      S_IFCHR | S_IRUSR | S_IWUSR, "dtlk");
-
        init_timer(&dtlk_timer);
        dtlk_timer.function = dtlk_timer_tick;
        init_waitqueue_head(&dtlk_process_list);
@@ -357,7 +353,6 @@ static void __exit dtlk_cleanup (void)
 
        dtlk_write_tts(DTLK_CLEAR);
        unregister_chrdev(dtlk_major, "dtlk");
-       devfs_remove("dtlk");
        release_region(dtlk_port_lpc, DTLK_IO_EXTENT);
 }
 
index 9cad8501d62c9fca6a93656c204bb1dea1e09a15..d0b3890d93021165572b53ef876f01729704ffb3 100644 (file)
@@ -80,7 +80,7 @@ static int invalid_lilo_config;
 /* The ISA boards do window flipping into the same spaces so its only sane
    with a single lock. It's still pretty efficient */
 
-static spinlock_t epca_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(epca_lock);
 
 /* -----------------------------------------------------------------------
        MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 
@@ -1232,7 +1232,6 @@ static int __init pc_init(void)
 
        pc_driver->owner = THIS_MODULE;
        pc_driver->name = "ttyD"; 
-       pc_driver->devfs_name = "tts/D";
        pc_driver->major = DIGI_MAJOR; 
        pc_driver->minor_start = 0;
        pc_driver->type = TTY_DRIVER_TYPE_SERIAL;
index 922174d527ae6325ed63562e1929f44892a9ded7..9827d170ca17ff7cc0726ef09fd83c90de64a3fd 100644 (file)
@@ -2449,7 +2449,6 @@ static int __init espserial_init(void)
        
        esp_driver->owner = THIS_MODULE;
        esp_driver->name = "ttyP";
-       esp_driver->devfs_name = "tts/P";
        esp_driver->major = ESP_IN_MAJOR;
        esp_driver->minor_start = 0;
        esp_driver->type = TTY_DRIVER_TYPE_SERIAL;
index 821357ce7e0e86c3a529b7c3ae8850e9a7e9404c..3eeb869a9a11f22dca28bff078f5d9ae96998c77 100644 (file)
@@ -33,7 +33,6 @@
 #endif
 #include <linux/fcntl.h>
 #include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
 
 #include <linux/zftape.h>
 #include <linux/init.h>
@@ -332,29 +331,11 @@ KERN_INFO
        zft_class = class_create(THIS_MODULE, "zft");
        for (i = 0; i < 4; i++) {
                class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i);
-               devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i),
-                               S_IFCHR | S_IRUSR | S_IWUSR,
-                               "qft%i", i);
                class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i);
-               devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4),
-                               S_IFCHR | S_IRUSR | S_IWUSR,
-                               "nqft%i", i);
                class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i);
-               devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16),
-                               S_IFCHR | S_IRUSR | S_IWUSR,
-                               "zqft%i", i);
                class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i);
-               devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20),
-                               S_IFCHR | S_IRUSR | S_IWUSR,
-                               "nzqft%i", i);
                class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i);
-               devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32),
-                               S_IFCHR | S_IRUSR | S_IWUSR,
-                               "rawqft%i", i);
                class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i);
-               devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36),
-                               S_IFCHR | S_IRUSR | S_IWUSR,
-                               "nrawqft%i", i);
        }
 
 #ifdef CONFIG_ZFT_COMPRESSOR
@@ -380,17 +361,11 @@ static void zft_exit(void)
                TRACE(ft_t_info, "successful");
        }
         for (i = 0; i < 4; i++) {
-               devfs_remove("qft%i", i);
                class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i));
-               devfs_remove("nqft%i", i);
                class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4));
-               devfs_remove("zqft%i", i);
                class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16));
-               devfs_remove("nzqft%i", i);
                class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20));
-               devfs_remove("rawqft%i", i);
                class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32));
-               devfs_remove("nrawqft%i", i);
                class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36));
        }
        class_destroy(zft_class);
index a5c6a9d7ff0805319d42ee5ceb03020058821c59..6e380aecea6a3ba04ecf53bb80a9009027b70894 100644 (file)
@@ -820,7 +820,6 @@ int __init hvc_init(void)
                return -ENOMEM;
 
        drv->owner = THIS_MODULE;
-       drv->devfs_name = "hvc/";
        drv->driver_name = "hvc";
        drv->name = "hvc";
        drv->major = HVC_MAJOR;
index 8d97b3911293bf46436bd743ae9c28aaad714316..130dedc37568bce89af0630870c1f111c04ca2f9 100644 (file)
@@ -1320,11 +1320,12 @@ static struct tty_operations hvcs_ops = {
 static int hvcs_alloc_index_list(int n)
 {
        int i;
+
        hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL);
        if (!hvcs_index_list)
                return -ENOMEM;
        hvcs_index_count = n;
-       for(i = 0; i < hvcs_index_count; i++)
+       for (i = 0; i < hvcs_index_count; i++)
                hvcs_index_list[i] = -1;
        return 0;
 }
@@ -1332,11 +1333,9 @@ static int hvcs_alloc_index_list(int n)
 static void hvcs_free_index_list(void)
 {
        /* Paranoia check to be thorough. */
-       if (hvcs_index_list) {
-               kfree(hvcs_index_list);
-               hvcs_index_list = NULL;
-               hvcs_index_count = 0;
-       }
+       kfree(hvcs_index_list);
+       hvcs_index_list = NULL;
+       hvcs_index_count = 0;
 }
 
 static int __init hvcs_module_init(void)
@@ -1364,7 +1363,6 @@ static int __init hvcs_module_init(void)
 
        hvcs_tty_driver->driver_name = hvcs_driver_name;
        hvcs_tty_driver->name = hvcs_device_node;
-       hvcs_tty_driver->devfs_name = hvcs_device_node;
 
        /*
         * We'll let the system assign us a major number, indicated by leaving
index a0370ed752ce01725b4458fb00335adb5ccb905f..7b04eb1532051846a6354650753e542fb5a00c75 100644 (file)
@@ -1154,7 +1154,6 @@ static int __init hvsi_init(void)
                return -ENOMEM;
 
        hvsi_driver->owner = THIS_MODULE;
-       hvsi_driver->devfs_name = "hvsi/";
        hvsi_driver->driver_name = "hvsi";
        hvsi_driver->name = "hvsi";
        hvsi_driver->major = HVSI_MAJOR;
index 9ab33c3d359fae4279f338e826280d06bda983ed..8619542766cb28cfdda56efc600c97bbe7afe4e8 100644 (file)
@@ -91,7 +91,6 @@
 #include <linux/module.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
@@ -414,9 +413,7 @@ cleanup_module(void)
                        /* free io addresses and Tibet */
                        release_region( ip2config.addr[i], 8 );
                        class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
-                       devfs_remove("ip2/ipl%d", i);
                        class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
-                       devfs_remove("ip2/stat%d", i);
                }
                /* Disable and remove interrupt handler. */
                if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { 
@@ -425,7 +422,6 @@ cleanup_module(void)
                }
        }
        class_destroy(ip2_class);
-       devfs_remove("ip2");
        if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) {
                printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
        }
@@ -675,7 +671,6 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
 
        ip2_tty_driver->owner               = THIS_MODULE;
        ip2_tty_driver->name                 = "ttyF";
-       ip2_tty_driver->devfs_name          = "tts/F";
        ip2_tty_driver->driver_name          = pcDriver_name;
        ip2_tty_driver->major                = IP2_TTY_MAJOR;
        ip2_tty_driver->minor_start          = 0;
@@ -683,7 +678,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
        ip2_tty_driver->subtype              = SERIAL_TYPE_NORMAL;
        ip2_tty_driver->init_termios         = tty_std_termios;
        ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
-       ip2_tty_driver->flags                = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       ip2_tty_driver->flags                = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        tty_set_operations(ip2_tty_driver, &ip2_ops);
 
        ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
@@ -724,26 +719,9 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
                                class_device_create(ip2_class, NULL,
                                                MKDEV(IP2_IPL_MAJOR, 4 * i),
                                                NULL, "ipl%d", i);
-                               err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i),
-                                               S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
-                                               "ip2/ipl%d", i);
-                               if (err) {
-                                       class_device_destroy(ip2_class,
-                                               MKDEV(IP2_IPL_MAJOR, 4 * i));
-                                       goto out_class;
-                               }
-
                                class_device_create(ip2_class, NULL,
                                                MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
                                                NULL, "stat%d", i);
-                               err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
-                                               S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
-                                               "ip2/stat%d", i);
-                               if (err) {
-                                       class_device_destroy(ip2_class,
-                                               MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
-                                       goto out_class;
-                               }
 
                            for ( box = 0; box < ABS_MAX_BOXES; ++box )
                            {
index e1c95374984cccb89fec0427b5185de80dab6785..da637adbbfaaf218ca26bc186ec772044b16c659 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/poll.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/ipmi.h>
 #include <linux/mutex.h>
 #include <linux/init.h>
@@ -804,9 +803,6 @@ static void ipmi_new_smi(int if_num, struct device *device)
        dev_t dev = MKDEV(ipmi_major, if_num);
        struct ipmi_reg_list *entry;
 
-       devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
-                     "ipmidev/%d", if_num);
-
        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry) {
                printk(KERN_ERR "ipmi_devintf: Unable to create the"
@@ -836,7 +832,6 @@ static void ipmi_smi_gone(int if_num)
        }
        class_device_destroy(ipmi_class, dev);
        mutex_unlock(&reg_list_mutex);
-       devfs_remove("ipmidev/%d", if_num);
 }
 
 static struct ipmi_smi_watcher smi_watcher =
@@ -872,8 +867,6 @@ static __init int init_ipmi_devintf(void)
                ipmi_major = rv;
        }
 
-       devfs_mk_dir(DEVICE_NAME);
-
        rv = ipmi_smi_watcher_register(&smi_watcher);
        if (rv) {
                unregister_chrdev(ipmi_major, DEVICE_NAME);
@@ -898,7 +891,6 @@ static __exit void cleanup_ipmi(void)
        mutex_unlock(&reg_list_mutex);
        class_destroy(ipmi_class);
        ipmi_smi_watcher_unregister(&smi_watcher);
-       devfs_remove(DEVICE_NAME);
        unregister_chrdev(ipmi_major, DEVICE_NAME);
 }
 module_exit(cleanup_ipmi);
index b03ddab1bef57bae9a81acd79d31c42297d364cd..ad26f4b997c5bc7508a2abe11a36bda7a65e4eab 100644 (file)
@@ -57,8 +57,7 @@ static int ipmi_init_msghandler(void);
 static int initialized = 0;
 
 #ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_ipmi_root = NULL;
-EXPORT_SYMBOL(proc_ipmi_root);
+static struct proc_dir_entry *proc_ipmi_root = NULL;
 #endif /* CONFIG_PROC_FS */
 
 #define MAX_EVENTS_IN_QUEUE    25
@@ -3739,11 +3738,8 @@ static int ipmi_init_msghandler(void)
        proc_ipmi_root->owner = THIS_MODULE;
 #endif /* CONFIG_PROC_FS */
 
-       init_timer(&ipmi_timer);
-       ipmi_timer.data = 0;
-       ipmi_timer.function = ipmi_timeout;
-       ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
-       add_timer(&ipmi_timer);
+       setup_timer(&ipmi_timer, ipmi_timeout, 0);
+       mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
 
        atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 
index 02a7dd7a8a55571cbf261e63a9dcdf3cf7fbb969..bd4f2248b758e40a87039a75359a403c14357cb7 100644 (file)
 #include <linux/mutex.h>
 #include <linux/kthread.h>
 #include <asm/irq.h>
-#ifdef CONFIG_HIGH_RES_TIMERS
-#include <linux/hrtime.h>
-# if defined(schedule_next_int)
-/* Old high-res timer code, do translations. */
-#  define get_arch_cycles(a) quick_update_jiffies_sub(a)
-#  define arch_cycles_per_jiffy cycles_per_jiffies
-# endif
-static inline void add_usec_to_timer(struct timer_list *t, long v)
-{
-       t->arch_cycle_expires += nsec_to_arch_cycle(v * 1000);
-       while (t->arch_cycle_expires >= arch_cycles_per_jiffy)
-       {
-               t->expires++;
-               t->arch_cycle_expires -= arch_cycles_per_jiffy;
-       }
-}
-#endif
 #include <linux/interrupt.h>
 #include <linux/rcupdate.h>
 #include <linux/ipmi_smi.h>
@@ -243,8 +226,6 @@ static int register_xaction_notifier(struct notifier_block * nb)
        return atomic_notifier_chain_register(&xaction_notifier_list, nb);
 }
 
-static void si_restart_short_timer(struct smi_info *smi_info);
-
 static void deliver_recv_msg(struct smi_info *smi_info,
                             struct ipmi_smi_msg *msg)
 {
@@ -768,7 +749,6 @@ static void sender(void                *send_info,
            && (smi_info->curr_msg == NULL))
        {
                start_next_msg(smi_info);
-               si_restart_short_timer(smi_info);
        }
        spin_unlock_irqrestore(&(smi_info->si_lock), flags);
 }
@@ -809,7 +789,7 @@ static int ipmi_thread(void *data)
                        /* do nothing */
                }
                else if (smi_result == SI_SM_CALL_WITH_DELAY)
-                       udelay(1);
+                       schedule();
                else
                        schedule_timeout_interruptible(1);
        }
@@ -833,37 +813,6 @@ static void request_events(void *send_info)
 
 static int initialized = 0;
 
-/* Must be called with interrupts off and with the si_lock held. */
-static void si_restart_short_timer(struct smi_info *smi_info)
-{
-#if defined(CONFIG_HIGH_RES_TIMERS)
-       unsigned long flags;
-       unsigned long jiffies_now;
-       unsigned long seq;
-
-       if (del_timer(&(smi_info->si_timer))) {
-               /* If we don't delete the timer, then it will go off
-                  immediately, anyway.  So we only process if we
-                  actually delete the timer. */
-
-               do {
-                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
-                       jiffies_now = jiffies;
-                       smi_info->si_timer.expires = jiffies_now;
-                       smi_info->si_timer.arch_cycle_expires
-                               = get_arch_cycles(jiffies_now);
-               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
-               add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
-
-               add_timer(&(smi_info->si_timer));
-               spin_lock_irqsave(&smi_info->count_lock, flags);
-               smi_info->timeout_restarts++;
-               spin_unlock_irqrestore(&smi_info->count_lock, flags);
-       }
-#endif
-}
-
 static void smi_timeout(unsigned long data)
 {
        struct smi_info   *smi_info = (struct smi_info *) data;
@@ -904,31 +853,15 @@ static void smi_timeout(unsigned long data)
        /* If the state machine asks for a short delay, then shorten
            the timer timeout. */
        if (smi_result == SI_SM_CALL_WITH_DELAY) {
-#if defined(CONFIG_HIGH_RES_TIMERS)
-               unsigned long seq;
-#endif
                spin_lock_irqsave(&smi_info->count_lock, flags);
                smi_info->short_timeouts++;
                spin_unlock_irqrestore(&smi_info->count_lock, flags);
-#if defined(CONFIG_HIGH_RES_TIMERS)
-               do {
-                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
-                       smi_info->si_timer.expires = jiffies;
-                       smi_info->si_timer.arch_cycle_expires
-                               = get_arch_cycles(smi_info->si_timer.expires);
-               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-               add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
-#else
                smi_info->si_timer.expires = jiffies + 1;
-#endif
        } else {
                spin_lock_irqsave(&smi_info->count_lock, flags);
                smi_info->long_timeouts++;
                spin_unlock_irqrestore(&smi_info->count_lock, flags);
                smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
-#if defined(CONFIG_HIGH_RES_TIMERS)
-               smi_info->si_timer.arch_cycle_expires = 0;
-#endif
        }
 
  do_add_timer:
index 8f8867170973ccb95960b57a90cd5e58dc9d5ddb..1a0a19c53605ed6f4c9f54afa70fbdbab2e002ea 100644 (file)
@@ -949,9 +949,10 @@ static int wdog_reboot_handler(struct notifier_block *this,
                        /* Disable the WDT if we are shutting down. */
                        ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
                        panic_halt_ipmi_set_timeout();
-               } else {
+               } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
                        /* Set a long timer to let the reboot happens, but
-                          reboot if it hangs. */
+                          reboot if it hangs, but only if the watchdog
+                          timer was already running. */
                        timeout = 120;
                        pretimeout = 0;
                        ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
@@ -973,16 +974,17 @@ static int wdog_panic_handler(struct notifier_block *this,
 {
        static int panic_event_handled = 0;
 
-       /* On a panic, if we have a panic timeout, make sure that the thing
-          reboots, even if it hangs during that panic. */
-       if (watchdog_user && !panic_event_handled) {
-               /* Make sure the panic doesn't hang, and make sure we
-                  do this only once. */
+       /* On a panic, if we have a panic timeout, make sure to extend
+          the watchdog timer to a reasonable value to complete the
+          panic, if the watchdog timer is running.  Plus the
+          pretimeout is meaningless at panic time. */
+       if (watchdog_user && !panic_event_handled &&
+           ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
+               /* Make sure we do this only once. */
                panic_event_handled = 1;
            
                timeout = 255;
                pretimeout = 0;
-               ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
                panic_halt_ipmi_set_timeout();
        }
 
index efaaa1937ab6dc2115e7d5057744213db9e3e75b..478bf4d7d0659ac14922eb76adfecfcb448a6cbd 100644 (file)
@@ -1581,7 +1581,6 @@ static int __devinit isicom_register_tty_driver(void)
 
        isicom_normal->owner                    = THIS_MODULE;
        isicom_normal->name                     = "ttyM";
-       isicom_normal->devfs_name               = "isicom/";
        isicom_normal->major                    = ISICOM_NMAJOR;
        isicom_normal->minor_start              = 0;
        isicom_normal->type                     = TTY_DRIVER_TYPE_SERIAL;
index ef20c1fc9c4c121cf51d7102096cfb55f3fd5227..c74e5660a9b7e244607007b1af933665348d97e7 100644 (file)
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/device.h>
 #include <linux/wait.h>
+#include <linux/eisa.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_PCI
 #include <linux/pci.h>
-#endif
 
 /*****************************************************************************/
 
@@ -137,6 +135,10 @@ static stlconf_t   stli_brdconf[] = {
 
 static int     stli_nrbrds = ARRAY_SIZE(stli_brdconf);
 
+/* stli_lock must NOT be taken holding brd_lock */
+static spinlock_t stli_lock;   /* TTY logic lock */
+static spinlock_t brd_lock;    /* Board logic lock */
+
 /*
  *     There is some experimental EISA board detection code in this driver.
  *     By default it is disabled, but for those that want to try it out,
@@ -173,14 +175,6 @@ static char        *stli_serialname = "ttyE";
 
 static struct tty_driver       *stli_serial;
 
-/*
- *     We will need to allocate a temporary write buffer for chars that
- *     come direct from user space. The problem is that a copy from user
- *     space might cause a page fault (typically on a system that is
- *     swapping!). All ports will share one buffer - since if the system
- *     is already swapping a shared buffer won't make things any worse.
- */
-static char                    *stli_tmpwritebuf;
 
 #define        STLI_TXBUFSIZE          4096
 
@@ -419,7 +413,7 @@ static int  stli_eisamempsize = ARRAY_SIZE(stli_eisamemprobeaddrs);
 #endif
 
 static struct pci_device_id istallion_pci_tbl[] = {
-       { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA), },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, istallion_pci_tbl);
@@ -682,7 +676,7 @@ static int  stli_startbrd(stlibrd_t *brdp);
 static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp);
 static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp);
 static int     stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
-static void    stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp);
+static void    stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp);
 static void    stli_poll(unsigned long arg);
 static int     stli_hostcmd(stlibrd_t *brdp, stliport_t *portp);
 static int     stli_initopen(stlibrd_t *brdp, stliport_t *portp);
@@ -693,7 +687,8 @@ static void stli_dohangup(void *arg);
 static int     stli_setport(stliport_t *portp);
 static int     stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
 static void    stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
-static void    stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp);
+static void    __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
+static void    stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp);
 static void    stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp);
 static void    stli_mkasysigs(asysigs_t *sp, int dtr, int rts);
 static long    stli_mktiocm(unsigned long sigvalue);
@@ -799,18 +794,8 @@ static struct class *istallion_class;
 
 static int __init istallion_module_init(void)
 {
-       unsigned long   flags;
-
-#ifdef DEBUG
-       printk("init_module()\n");
-#endif
-
-       save_flags(flags);
-       cli();
        stli_init();
-       restore_flags(flags);
-
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -819,56 +804,43 @@ static void __exit istallion_module_exit(void)
 {
        stlibrd_t       *brdp;
        stliport_t      *portp;
-       unsigned long   flags;
        int             i, j;
 
-#ifdef DEBUG
-       printk("cleanup_module()\n");
-#endif
-
        printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
                stli_drvversion);
 
-       save_flags(flags);
-       cli();
-
-/*
- *     Free up all allocated resources used by the ports. This includes
- *     memory and interrupts.
- */
+       /*
+        *      Free up all allocated resources used by the ports. This includes
+        *      memory and interrupts.
+        */
        if (stli_timeron) {
                stli_timeron = 0;
-               del_timer(&stli_timerlist);
+               del_timer_sync(&stli_timerlist);
        }
 
        i = tty_unregister_driver(stli_serial);
        if (i) {
                printk("STALLION: failed to un-register tty driver, "
                        "errno=%d\n", -i);
-               restore_flags(flags);
                return;
        }
        put_tty_driver(stli_serial);
-       for (i = 0; i < 4; i++) {
-               devfs_remove("staliomem/%d", i);
+       for (i = 0; i < 4; i++)
                class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i));
-       }
-       devfs_remove("staliomem");
        class_destroy(istallion_class);
        if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
                printk("STALLION: failed to un-register serial memory device, "
                        "errno=%d\n", -i);
 
-       kfree(stli_tmpwritebuf);
        kfree(stli_txcookbuf);
 
        for (i = 0; (i < stli_nrbrds); i++) {
-               if ((brdp = stli_brds[i]) == (stlibrd_t *) NULL)
+               if ((brdp = stli_brds[i]) == NULL)
                        continue;
                for (j = 0; (j < STL_MAXPORTS); j++) {
                        portp = brdp->ports[j];
-                       if (portp != (stliport_t *) NULL) {
-                               if (portp->tty != (struct tty_struct *) NULL)
+                       if (portp != NULL) {
+                               if (portp->tty != NULL)
                                        tty_hangup(portp->tty);
                                kfree(portp);
                        }
@@ -878,10 +850,8 @@ static void __exit istallion_module_exit(void)
                if (brdp->iosize > 0)
                        release_region(brdp->iobase, brdp->iosize);
                kfree(brdp);
-               stli_brds[i] = (stlibrd_t *) NULL;
+               stli_brds[i] = NULL;
        }
-
-       restore_flags(flags);
 }
 
 module_init(istallion_module_init);
@@ -895,19 +865,15 @@ module_exit(istallion_module_exit);
 
 static void stli_argbrds(void)
 {
-       stlconf_t       conf;
-       stlibrd_t       *brdp;
-       int             i;
-
-#ifdef DEBUG
-       printk("stli_argbrds()\n");
-#endif
+       stlconf_t conf;
+       stlibrd_t *brdp;
+       int i;
 
        for (i = stli_nrbrds; i < ARRAY_SIZE(stli_brdsp); i++) {
                memset(&conf, 0, sizeof(conf));
                if (stli_parsebrd(&conf, stli_brdsp[i]) == 0)
                        continue;
-               if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
+               if ((brdp = stli_allocbrd()) == NULL)
                        continue;
                stli_nrbrds = i + 1;
                brdp->brdnr = i;
@@ -926,9 +892,9 @@ static void stli_argbrds(void)
 
 static unsigned long stli_atol(char *str)
 {
-       unsigned long   val;
-       int             base, c;
-       char            *sp;
+       unsigned long val;
+       int base, c;
+       char *sp;
 
        val = 0;
        sp = str;
@@ -962,15 +928,11 @@ static unsigned long stli_atol(char *str)
 
 static int stli_parsebrd(stlconf_t *confp, char **argp)
 {
-       char    *sp;
-       int     i;
-
-#ifdef DEBUG
-       printk("stli_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp);
-#endif
+       char *sp;
+       int i;
 
-       if ((argp[0] == (char *) NULL) || (*argp[0] == 0))
-               return(0);
+       if (argp[0] == NULL || *argp[0] == 0)
+               return 0;
 
        for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
                *sp = TOLOWER(*sp);
@@ -985,9 +947,9 @@ static int stli_parsebrd(stlconf_t *confp, char **argp)
        }
 
        confp->brdtype = stli_brdstr[i].type;
-       if ((argp[1] != (char *) NULL) && (*argp[1] != 0))
+       if (argp[1] != NULL && *argp[1] != 0)
                confp->ioaddr1 = stli_atol(argp[1]);
-       if ((argp[2] != (char *) NULL) && (*argp[2] != 0))
+       if (argp[2] !=  NULL && *argp[2] != 0)
                confp->memaddr = stli_atol(argp[2]);
        return(1);
 }
@@ -998,34 +960,29 @@ static int stli_parsebrd(stlconf_t *confp, char **argp)
 
 static int stli_open(struct tty_struct *tty, struct file *filp)
 {
-       stlibrd_t       *brdp;
-       stliport_t      *portp;
-       unsigned int    minordev;
-       int             brdnr, portnr, rc;
-
-#ifdef DEBUG
-       printk("stli_open(tty=%x,filp=%x): device=%s\n", (int) tty,
-               (int) filp, tty->name);
-#endif
+       stlibrd_t *brdp;
+       stliport_t *portp;
+       unsigned int minordev;
+       int brdnr, portnr, rc;
 
        minordev = tty->index;
        brdnr = MINOR2BRD(minordev);
        if (brdnr >= stli_nrbrds)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stli_brds[brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
        if ((brdp->state & BST_STARTED) == 0)
-               return(-ENODEV);
+               return -ENODEV;
        portnr = MINOR2PORT(minordev);
        if ((portnr < 0) || (portnr > brdp->nrports))
-               return(-ENODEV);
+               return -ENODEV;
 
        portp = brdp->ports[portnr];
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
+       if (portp == NULL)
+               return -ENODEV;
        if (portp->devnr < 1)
-               return(-ENODEV);
+               return -ENODEV;
 
 
 /*
@@ -1037,8 +994,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        if (portp->flags & ASYNC_CLOSING) {
                interruptible_sleep_on(&portp->close_wait);
                if (portp->flags & ASYNC_HUP_NOTIFY)
-                       return(-EAGAIN);
-               return(-ERESTARTSYS);
+                       return -EAGAIN;
+               return -ERESTARTSYS;
        }
 
 /*
@@ -1054,7 +1011,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_INITIALIZING, &portp->state));
        if (signal_pending(current))
-               return(-ERESTARTSYS);
+               return -ERESTARTSYS;
 
        if ((portp->flags & ASYNC_INITIALIZED) == 0) {
                set_bit(ST_INITIALIZING, &portp->state);
@@ -1065,7 +1022,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
                clear_bit(ST_INITIALIZING, &portp->state);
                wake_up_interruptible(&portp->raw_wait);
                if (rc < 0)
-                       return(rc);
+                       return rc;
        }
 
 /*
@@ -1077,8 +1034,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        if (portp->flags & ASYNC_CLOSING) {
                interruptible_sleep_on(&portp->close_wait);
                if (portp->flags & ASYNC_HUP_NOTIFY)
-                       return(-EAGAIN);
-               return(-ERESTARTSYS);
+                       return -EAGAIN;
+               return -ERESTARTSYS;
        }
 
 /*
@@ -1088,38 +1045,33 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
  */
        if (!(filp->f_flags & O_NONBLOCK)) {
                if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
-                       return(rc);
+                       return rc;
        }
        portp->flags |= ASYNC_NORMAL_ACTIVE;
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
 
 static void stli_close(struct tty_struct *tty, struct file *filp)
 {
-       stlibrd_t       *brdp;
-       stliport_t      *portp;
-       unsigned long   flags;
-
-#ifdef DEBUG
-       printk("stli_close(tty=%x,filp=%x)\n", (int) tty, (int) filp);
-#endif
+       stlibrd_t *brdp;
+       stliport_t *portp;
+       unsigned long flags;
 
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&stli_lock, flags);
        if (tty_hung_up_p(filp)) {
-               restore_flags(flags);
+               spin_unlock_irqrestore(&stli_lock, flags);
                return;
        }
        if ((tty->count == 1) && (portp->refcount != 1))
                portp->refcount = 1;
        if (portp->refcount-- > 1) {
-               restore_flags(flags);
+               spin_unlock_irqrestore(&stli_lock, flags);
                return;
        }
 
@@ -1134,6 +1086,8 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        if (tty == stli_txcooktty)
                stli_flushchars(tty);
        tty->closing = 1;
+       spin_unlock_irqrestore(&stli_lock, flags);
+
        if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
                tty_wait_until_sent(tty, portp->closing_wait);
 
@@ -1157,7 +1111,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        stli_flushbuffer(tty);
 
        tty->closing = 0;
-       portp->tty = (struct tty_struct *) NULL;
+       portp->tty = NULL;
 
        if (portp->openwaitcnt) {
                if (portp->close_delay)
@@ -1167,7 +1121,6 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
 
        portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
        wake_up_interruptible(&portp->close_wait);
-       restore_flags(flags);
 }
 
 /*****************************************************************************/
@@ -1182,45 +1135,41 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
 
 static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
 {
-       struct tty_struct       *tty;
-       asynotify_t             nt;
-       asyport_t               aport;
-       int                     rc;
-
-#ifdef DEBUG
-       printk("stli_initopen(brdp=%x,portp=%x)\n", (int) brdp, (int) portp);
-#endif
+       struct tty_struct *tty;
+       asynotify_t nt;
+       asyport_t aport;
+       int rc;
 
        if ((rc = stli_rawopen(brdp, portp, 0, 1)) < 0)
-               return(rc);
+               return rc;
 
        memset(&nt, 0, sizeof(asynotify_t));
        nt.data = (DT_TXLOW | DT_TXEMPTY | DT_RXBUSY | DT_RXBREAK);
        nt.signal = SG_DCD;
        if ((rc = stli_cmdwait(brdp, portp, A_SETNOTIFY, &nt,
            sizeof(asynotify_t), 0)) < 0)
-               return(rc);
+               return rc;
 
        tty = portp->tty;
-       if (tty == (struct tty_struct *) NULL)
-               return(-ENODEV);
+       if (tty == NULL)
+               return -ENODEV;
        stli_mkasyport(portp, &aport, tty->termios);
        if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport,
            sizeof(asyport_t), 0)) < 0)
-               return(rc);
+               return rc;
 
        set_bit(ST_GETSIGS, &portp->state);
        if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig,
            sizeof(asysigs_t), 1)) < 0)
-               return(rc);
+               return rc;
        if (test_and_clear_bit(ST_GETSIGS, &portp->state))
                portp->sigs = stli_mktiocm(portp->asig.sigvalue);
        stli_mkasysigs(&portp->asig, 1, 1);
        if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
            sizeof(asysigs_t), 0)) < 0)
-               return(rc);
+               return rc;
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -1234,22 +1183,15 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
 
 static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait)
 {
-       volatile cdkhdr_t       *hdrp;
-       volatile cdkctrl_t      *cp;
-       volatile unsigned char  *bits;
-       unsigned long           flags;
-       int                     rc;
-
-#ifdef DEBUG
-       printk("stli_rawopen(brdp=%x,portp=%x,arg=%x,wait=%d)\n",
-               (int) brdp, (int) portp, (int) arg, wait);
-#endif
+       cdkhdr_t __iomem *hdrp;
+       cdkctrl_t __iomem *cp;
+       unsigned char __iomem *bits;
+       unsigned long flags;
+       int rc;
 
 /*
  *     Send a message to the slave to open this port.
  */
-       save_flags(flags);
-       cli();
 
 /*
  *     Slave is already closing this port. This can happen if a hangup
@@ -1260,7 +1202,6 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_CLOSING, &portp->state));
        if (signal_pending(current)) {
-               restore_flags(flags);
                return -ERESTARTSYS;
        }
 
@@ -1269,19 +1210,20 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
  *     memory. Once the message is in set the service bits to say that
  *     this port wants service.
  */
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
-       cp->openarg = arg;
-       cp->open = 1;
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+       cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
+       writel(arg, &cp->openarg);
+       writeb(1, &cp->open);
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
                portp->portidx;
-       *bits |= portp->portbit;
+       writeb(readb(bits) | portp->portbit, bits);
        EBRDDISABLE(brdp);
 
        if (wait == 0) {
-               restore_flags(flags);
-               return(0);
+               spin_unlock_irqrestore(&brd_lock, flags);
+               return 0;
        }
 
 /*
@@ -1290,15 +1232,16 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
  */
        rc = 0;
        set_bit(ST_OPENING, &portp->state);
+       spin_unlock_irqrestore(&brd_lock, flags);
+
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_OPENING, &portp->state));
        if (signal_pending(current))
                rc = -ERESTARTSYS;
-       restore_flags(flags);
 
        if ((rc == 0) && (portp->rc != 0))
                rc = -EIO;
-       return(rc);
+       return rc;
 }
 
 /*****************************************************************************/
@@ -1311,19 +1254,11 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
 
 static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait)
 {
-       volatile cdkhdr_t       *hdrp;
-       volatile cdkctrl_t      *cp;
-       volatile unsigned char  *bits;
-       unsigned long           flags;
-       int                     rc;
-
-#ifdef DEBUG
-       printk("stli_rawclose(brdp=%x,portp=%x,arg=%x,wait=%d)\n",
-               (int) brdp, (int) portp, (int) arg, wait);
-#endif
-
-       save_flags(flags);
-       cli();
+       cdkhdr_t __iomem *hdrp;
+       cdkctrl_t __iomem *cp;
+       unsigned char __iomem *bits;
+       unsigned long flags;
+       int rc;
 
 /*
  *     Slave is already closing this port. This can happen if a hangup
@@ -1333,7 +1268,6 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
                wait_event_interruptible(portp->raw_wait,
                                !test_bit(ST_CLOSING, &portp->state));
                if (signal_pending(current)) {
-                       restore_flags(flags);
                        return -ERESTARTSYS;
                }
        }
@@ -1341,21 +1275,22 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
 /*
  *     Write the close command into shared memory.
  */
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
-       cp->closearg = arg;
-       cp->close = 1;
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+       cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
+       writel(arg, &cp->closearg);
+       writeb(1, &cp->close);
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
                portp->portidx;
-       *bits |= portp->portbit;
+       writeb(readb(bits) |portp->portbit, bits);
        EBRDDISABLE(brdp);
 
        set_bit(ST_CLOSING, &portp->state);
-       if (wait == 0) {
-               restore_flags(flags);
-               return(0);
-       }
+       spin_unlock_irqrestore(&brd_lock, flags);
+
+       if (wait == 0)
+               return 0;
 
 /*
  *     Slave is in action, so now we must wait for the open acknowledgment
@@ -1366,11 +1301,10 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
                        !test_bit(ST_CLOSING, &portp->state));
        if (signal_pending(current))
                rc = -ERESTARTSYS;
-       restore_flags(flags);
 
        if ((rc == 0) && (portp->rc != 0))
                rc = -EIO;
-       return(rc);
+       return rc;
 }
 
 /*****************************************************************************/
@@ -1384,36 +1318,21 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
 
 static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
 {
-       unsigned long   flags;
-
-#ifdef DEBUG
-       printk("stli_cmdwait(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,"
-               "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd,
-               (int) arg, size, copyback);
-#endif
-
-       save_flags(flags);
-       cli();
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_CMDING, &portp->state));
-       if (signal_pending(current)) {
-               restore_flags(flags);
+       if (signal_pending(current))
                return -ERESTARTSYS;
-       }
 
        stli_sendcmd(brdp, portp, cmd, arg, size, copyback);
 
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_CMDING, &portp->state));
-       if (signal_pending(current)) {
-               restore_flags(flags);
+       if (signal_pending(current))
                return -ERESTARTSYS;
-       }
-       restore_flags(flags);
 
        if (portp->rc != 0)
-               return(-EIO);
-       return(0);
+               return -EIO;
+       return 0;
 }
 
 /*****************************************************************************/
@@ -1425,22 +1344,18 @@ static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, v
 
 static int stli_setport(stliport_t *portp)
 {
-       stlibrd_t       *brdp;
-       asyport_t       aport;
-
-#ifdef DEBUG
-       printk("stli_setport(portp=%x)\n", (int) portp);
-#endif
+       stlibrd_t *brdp;
+       asyport_t aport;
 
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
-       if (portp->tty == (struct tty_struct *) NULL)
-               return(-ENODEV);
-       if ((portp->brdnr < 0) && (portp->brdnr >= stli_nrbrds))
-               return(-ENODEV);
+       if (portp == NULL)
+               return -ENODEV;
+       if (portp->tty == NULL)
+               return -ENODEV;
+       if (portp->brdnr < 0 && portp->brdnr >= stli_nrbrds)
+               return -ENODEV;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
 
        stli_mkasyport(portp, &aport, portp->tty->termios);
        return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
@@ -1455,13 +1370,8 @@ static int stli_setport(stliport_t *portp)
 
 static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp)
 {
-       unsigned long   flags;
-       int             rc, doclocal;
-
-#ifdef DEBUG
-       printk("stli_waitcarrier(brdp=%x,portp=%x,filp=%x)\n",
-               (int) brdp, (int) portp, (int) filp);
-#endif
+       unsigned long flags;
+       int rc, doclocal;
 
        rc = 0;
        doclocal = 0;
@@ -1469,11 +1379,11 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
        if (portp->tty->termios->c_cflag & CLOCAL)
                doclocal++;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&stli_lock, flags);
        portp->openwaitcnt++;
        if (! tty_hung_up_p(filp))
                portp->refcount--;
+       spin_unlock_irqrestore(&stli_lock, flags);
 
        for (;;) {
                stli_mkasysigs(&portp->asig, 1, 1);
@@ -1499,12 +1409,13 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
                interruptible_sleep_on(&portp->open_wait);
        }
 
+       spin_lock_irqsave(&stli_lock, flags);
        if (! tty_hung_up_p(filp))
                portp->refcount++;
        portp->openwaitcnt--;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&stli_lock, flags);
 
-       return(rc);
+       return rc;
 }
 
 /*****************************************************************************/
@@ -1517,46 +1428,38 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
 
 static int stli_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
-       volatile cdkasy_t       *ap;
-       volatile cdkhdr_t       *hdrp;
-       volatile unsigned char  *bits;
-       unsigned char           *shbuf, *chbuf;
-       stliport_t              *portp;
-       stlibrd_t               *brdp;
-       unsigned int            len, stlen, head, tail, size;
-       unsigned long           flags;
-
-#ifdef DEBUG
-       printk("stli_write(tty=%x,buf=%x,count=%d)\n",
-               (int) tty, (int) buf, count);
-#endif
+       cdkasy_t __iomem *ap;
+       cdkhdr_t __iomem *hdrp;
+       unsigned char __iomem *bits;
+       unsigned char __iomem *shbuf;
+       unsigned char *chbuf;
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned int len, stlen, head, tail, size;
+       unsigned long flags;
 
-       if ((tty == (struct tty_struct *) NULL) ||
-           (stli_tmpwritebuf == (char *) NULL))
-               return(0);
        if (tty == stli_txcooktty)
                stli_flushchars(tty);
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return(0);
+       if (portp == NULL)
+               return 0;
        if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
        chbuf = (unsigned char *) buf;
 
 /*
  *     All data is now local, shove as much as possible into shared memory.
  */
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
-       head = (unsigned int) ap->txq.head;
-       tail = (unsigned int) ap->txq.tail;
-       if (tail != ((unsigned int) ap->txq.tail))
-               tail = (unsigned int) ap->txq.tail;
+       ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+       head = (unsigned int) readw(&ap->txq.head);
+       tail = (unsigned int) readw(&ap->txq.tail);
+       if (tail != ((unsigned int) readw(&ap->txq.tail)))
+               tail = (unsigned int) readw(&ap->txq.tail);
        size = portp->txsize;
        if (head >= tail) {
                len = size - (head - tail) - 1;
@@ -1568,11 +1471,11 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
 
        len = MIN(len, count);
        count = 0;
-       shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset);
+       shbuf = (char __iomem *) EBRDGETMEMPTR(brdp, portp->txoffset);
 
        while (len > 0) {
                stlen = MIN(len, stlen);
-               memcpy((shbuf + head), chbuf, stlen);
+               memcpy_toio(shbuf + head, chbuf, stlen);
                chbuf += stlen;
                len -= stlen;
                count += stlen;
@@ -1583,20 +1486,19 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
                }
        }
 
-       ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
-       ap->txq.head = head;
+       ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+       writew(head, &ap->txq.head);
        if (test_bit(ST_TXBUSY, &portp->state)) {
-               if (ap->changed.data & DT_TXEMPTY)
-                       ap->changed.data &= ~DT_TXEMPTY;
+               if (readl(&ap->changed.data) & DT_TXEMPTY)
+                       writel(readl(&ap->changed.data) & ~DT_TXEMPTY, &ap->changed.data);
        }
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
                portp->portidx;
-       *bits |= portp->portbit;
+       writeb(readb(bits) | portp->portbit, bits);
        set_bit(ST_TXBUSY, &portp->state);
        EBRDDISABLE(brdp);
-
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        return(count);
 }
@@ -1613,14 +1515,8 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
 
 static void stli_putchar(struct tty_struct *tty, unsigned char ch)
 {
-#ifdef DEBUG
-       printk("stli_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
        if (tty != stli_txcooktty) {
-               if (stli_txcooktty != (struct tty_struct *) NULL)
+               if (stli_txcooktty != NULL)
                        stli_flushchars(stli_txcooktty);
                stli_txcooktty = tty;
        }
@@ -1640,29 +1536,26 @@ static void stli_putchar(struct tty_struct *tty, unsigned char ch)
 
 static void stli_flushchars(struct tty_struct *tty)
 {
-       volatile cdkhdr_t       *hdrp;
-       volatile unsigned char  *bits;
-       volatile cdkasy_t       *ap;
-       struct tty_struct       *cooktty;
-       stliport_t              *portp;
-       stlibrd_t               *brdp;
-       unsigned int            len, stlen, head, tail, size, count, cooksize;
-       unsigned char           *buf, *shbuf;
-       unsigned long           flags;
-
-#ifdef DEBUG
-       printk("stli_flushchars(tty=%x)\n", (int) tty);
-#endif
+       cdkhdr_t __iomem *hdrp;
+       unsigned char __iomem *bits;
+       cdkasy_t __iomem *ap;
+       struct tty_struct *cooktty;
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned int len, stlen, head, tail, size, count, cooksize;
+       unsigned char *buf;
+       unsigned char __iomem *shbuf;
+       unsigned long flags;
 
        cooksize = stli_txcooksize;
        cooktty = stli_txcooktty;
        stli_txcooksize = 0;
        stli_txcookrealsize = 0;
-       stli_txcooktty = (struct tty_struct *) NULL;
+       stli_txcooktty = NULL;
 
-       if (tty == (struct tty_struct *) NULL)
+       if (tty == NULL)
                return;
-       if (cooktty == (struct tty_struct *) NULL)
+       if (cooktty == NULL)
                return;
        if (tty != cooktty)
                tty = cooktty;
@@ -1670,23 +1563,22 @@ static void stli_flushchars(struct tty_struct *tty)
                return;
 
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
        if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
 
-       ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
-       head = (unsigned int) ap->txq.head;
-       tail = (unsigned int) ap->txq.tail;
-       if (tail != ((unsigned int) ap->txq.tail))
-               tail = (unsigned int) ap->txq.tail;
+       ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+       head = (unsigned int) readw(&ap->txq.head);
+       tail = (unsigned int) readw(&ap->txq.tail);
+       if (tail != ((unsigned int) readw(&ap->txq.tail)))
+               tail = (unsigned int) readw(&ap->txq.tail);
        size = portp->txsize;
        if (head >= tail) {
                len = size - (head - tail) - 1;
@@ -1703,7 +1595,7 @@ static void stli_flushchars(struct tty_struct *tty)
 
        while (len > 0) {
                stlen = MIN(len, stlen);
-               memcpy((shbuf + head), buf, stlen);
+               memcpy_toio(shbuf + head, buf, stlen);
                buf += stlen;
                len -= stlen;
                count += stlen;
@@ -1714,73 +1606,66 @@ static void stli_flushchars(struct tty_struct *tty)
                }
        }
 
-       ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
-       ap->txq.head = head;
+       ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+       writew(head, &ap->txq.head);
 
        if (test_bit(ST_TXBUSY, &portp->state)) {
-               if (ap->changed.data & DT_TXEMPTY)
-                       ap->changed.data &= ~DT_TXEMPTY;
+               if (readl(&ap->changed.data) & DT_TXEMPTY)
+                       writel(readl(&ap->changed.data) & ~DT_TXEMPTY, &ap->changed.data);
        }
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
                portp->portidx;
-       *bits |= portp->portbit;
+       writeb(readb(bits) | portp->portbit, bits);
        set_bit(ST_TXBUSY, &portp->state);
 
        EBRDDISABLE(brdp);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
 
 static int stli_writeroom(struct tty_struct *tty)
 {
-       volatile cdkasyrq_t     *rp;
-       stliport_t              *portp;
-       stlibrd_t               *brdp;
-       unsigned int            head, tail, len;
-       unsigned long           flags;
-
-#ifdef DEBUG
-       printk("stli_writeroom(tty=%x)\n", (int) tty);
-#endif
+       cdkasyrq_t __iomem *rp;
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned int head, tail, len;
+       unsigned long flags;
 
-       if (tty == (struct tty_struct *) NULL)
-               return(0);
        if (tty == stli_txcooktty) {
                if (stli_txcookrealsize != 0) {
                        len = stli_txcookrealsize - stli_txcooksize;
-                       return(len);
+                       return len;
                }
        }
 
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return(0);
+       if (portp == NULL)
+               return 0;
        if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
-       head = (unsigned int) rp->head;
-       tail = (unsigned int) rp->tail;
-       if (tail != ((unsigned int) rp->tail))
-               tail = (unsigned int) rp->tail;
+       rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
+       head = (unsigned int) readw(&rp->head);
+       tail = (unsigned int) readw(&rp->tail);
+       if (tail != ((unsigned int) readw(&rp->tail)))
+               tail = (unsigned int) readw(&rp->tail);
        len = (head >= tail) ? (portp->txsize - (head - tail)) : (tail - head);
        len--;
        EBRDDISABLE(brdp);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        if (tty == stli_txcooktty) {
                stli_txcookrealsize = len;
                len -= stli_txcooksize;
        }
-       return(len);
+       return len;
 }
 
 /*****************************************************************************/
@@ -1795,44 +1680,37 @@ static int stli_writeroom(struct tty_struct *tty)
 
 static int stli_charsinbuffer(struct tty_struct *tty)
 {
-       volatile cdkasyrq_t     *rp;
-       stliport_t              *portp;
-       stlibrd_t               *brdp;
-       unsigned int            head, tail, len;
-       unsigned long           flags;
-
-#ifdef DEBUG
-       printk("stli_charsinbuffer(tty=%x)\n", (int) tty);
-#endif
+       cdkasyrq_t __iomem *rp;
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned int head, tail, len;
+       unsigned long flags;
 
-       if (tty == (struct tty_struct *) NULL)
-               return(0);
        if (tty == stli_txcooktty)
                stli_flushchars(tty);
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return(0);
+       if (portp == NULL)
+               return 0;
        if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
-       head = (unsigned int) rp->head;
-       tail = (unsigned int) rp->tail;
-       if (tail != ((unsigned int) rp->tail))
-               tail = (unsigned int) rp->tail;
+       rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
+       head = (unsigned int) readw(&rp->head);
+       tail = (unsigned int) readw(&rp->tail);
+       if (tail != ((unsigned int) readw(&rp->tail)))
+               tail = (unsigned int) readw(&rp->tail);
        len = (head >= tail) ? (head - tail) : (portp->txsize - (tail - head));
        if ((len == 0) && test_bit(ST_TXBUSY, &portp->state))
                len = 1;
        EBRDDISABLE(brdp);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
-       return(len);
+       return len;
 }
 
 /*****************************************************************************/
@@ -1843,12 +1721,8 @@ static int stli_charsinbuffer(struct tty_struct *tty)
 
 static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
 {
-       struct serial_struct    sio;
-       stlibrd_t               *brdp;
-
-#ifdef DEBUG
-       printk("stli_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
-#endif
+       struct serial_struct sio;
+       stlibrd_t *brdp;
 
        memset(&sio, 0, sizeof(struct serial_struct));
        sio.type = PORT_UNKNOWN;
@@ -1863,7 +1737,7 @@ static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
        sio.hub6 = 0;
 
        brdp = stli_brds[portp->brdnr];
-       if (brdp != (stlibrd_t *) NULL)
+       if (brdp != NULL)
                sio.port = brdp->iobase;
                
        return copy_to_user(sp, &sio, sizeof(struct serial_struct)) ?
@@ -1880,12 +1754,8 @@ static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
 
 static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
 {
-       struct serial_struct    sio;
-       int                     rc;
-
-#ifdef DEBUG
-       printk("stli_setserial(portp=%p,sp=%p)\n", portp, sp);
-#endif
+       struct serial_struct sio;
+       int rc;
 
        if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
                return -EFAULT;
@@ -1894,7 +1764,7 @@ static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
                    (sio.close_delay != portp->close_delay) ||
                    ((sio.flags & ~ASYNC_USR_MASK) !=
                    (portp->flags & ~ASYNC_USR_MASK)))
-                       return(-EPERM);
+                       return -EPERM;
        } 
 
        portp->flags = (portp->flags & ~ASYNC_USR_MASK) |
@@ -1905,8 +1775,8 @@ static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
        portp->custom_divisor = sio.custom_divisor;
 
        if ((rc = stli_setport(portp)) < 0)
-               return(rc);
-       return(0);
+               return rc;
+       return 0;
 }
 
 /*****************************************************************************/
@@ -1917,19 +1787,19 @@ static int stli_tiocmget(struct tty_struct *tty, struct file *file)
        stlibrd_t *brdp;
        int rc;
 
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+       if (portp == NULL)
+               return -ENODEV;
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
        if (tty->flags & (1 << TTY_IO_ERROR))
-               return(-EIO);
+               return -EIO;
 
        if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS,
                               &portp->asig, sizeof(asysigs_t), 1)) < 0)
-               return(rc);
+               return rc;
 
        return stli_mktiocm(portp->asig.sigvalue);
 }
@@ -1941,15 +1811,15 @@ static int stli_tiocmset(struct tty_struct *tty, struct file *file,
        stlibrd_t *brdp;
        int rts = -1, dtr = -1;
 
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+       if (portp == NULL)
+               return -ENODEV;
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
        if (tty->flags & (1 << TTY_IO_ERROR))
-               return(-EIO);
+               return -EIO;
 
        if (set & TIOCM_RTS)
                rts = 1;
@@ -1968,32 +1838,25 @@ static int stli_tiocmset(struct tty_struct *tty, struct file *file,
 
 static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
 {
-       stliport_t      *portp;
-       stlibrd_t       *brdp;
-       unsigned int    ival;
-       int             rc;
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned int ival;
+       int rc;
        void __user *argp = (void __user *)arg;
 
-#ifdef DEBUG
-       printk("stli_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n",
-               (int) tty, (int) file, cmd, (int) arg);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return(-ENODEV);
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return(0);
+       if (portp == NULL)
+               return -ENODEV;
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+               return 0;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(0);
+       if (brdp == NULL)
+               return 0;
 
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
            (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) {
                if (tty->flags & (1 << TTY_IO_ERROR))
-                       return(-EIO);
+                       return -EIO;
        }
 
        rc = 0;
@@ -2040,7 +1903,7 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
                break;
        }
 
-       return(rc);
+       return rc;
 }
 
 /*****************************************************************************/
@@ -2052,24 +1915,20 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
 
 static void stli_settermios(struct tty_struct *tty, struct termios *old)
 {
-       stliport_t      *portp;
-       stlibrd_t       *brdp;
-       struct termios  *tiosp;
-       asyport_t       aport;
-
-#ifdef DEBUG
-       printk("stli_settermios(tty=%x,old=%x)\n", (int) tty, (int) old);
-#endif
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       struct termios *tiosp;
+       asyport_t aport;
 
-       if (tty == (struct tty_struct *) NULL)
+       if (tty == NULL)
                return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
        tiosp = tty->termios;
@@ -2102,18 +1961,9 @@ static void stli_settermios(struct tty_struct *tty, struct termios *old)
 
 static void stli_throttle(struct tty_struct *tty)
 {
-       stliport_t      *portp;
-
-#ifdef DEBUG
-       printk("stli_throttle(tty=%x)\n", (int) tty);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
-       portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       stliport_t      *portp = tty->driver_data;
+       if (portp == NULL)
                return;
-
        set_bit(ST_RXSTOP, &portp->state);
 }
 
@@ -2127,88 +1977,30 @@ static void stli_throttle(struct tty_struct *tty)
 
 static void stli_unthrottle(struct tty_struct *tty)
 {
-       stliport_t      *portp;
-
-#ifdef DEBUG
-       printk("stli_unthrottle(tty=%x)\n", (int) tty);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
+       stliport_t      *portp = tty->driver_data;
+       if (portp == NULL)
                return;
-       portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return;
-
        clear_bit(ST_RXSTOP, &portp->state);
 }
 
 /*****************************************************************************/
 
 /*
- *     Stop the transmitter. Basically to do this we will just turn TX
- *     interrupts off.
+ *     Stop the transmitter.
  */
 
 static void stli_stop(struct tty_struct *tty)
 {
-       stlibrd_t       *brdp;
-       stliport_t      *portp;
-       asyctrl_t       actrl;
-
-#ifdef DEBUG
-       printk("stli_stop(tty=%x)\n", (int) tty);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
-       portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return;
-       brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return;
-
-       memset(&actrl, 0, sizeof(asyctrl_t));
-       actrl.txctrl = CT_STOPFLOW;
-#if 0
-       stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
-#endif
 }
 
 /*****************************************************************************/
 
 /*
- *     Start the transmitter again. Just turn TX interrupts back on.
+ *     Start the transmitter again.
  */
 
 static void stli_start(struct tty_struct *tty)
 {
-       stliport_t      *portp;
-       stlibrd_t       *brdp;
-       asyctrl_t       actrl;
-
-#ifdef DEBUG
-       printk("stli_start(tty=%x)\n", (int) tty);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
-       portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
-               return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
-               return;
-       brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return;
-
-       memset(&actrl, 0, sizeof(asyctrl_t));
-       actrl.txctrl = CT_STARTFLOW;
-#if 0
-       stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
-#endif
 }
 
 /*****************************************************************************/
@@ -2224,22 +2016,9 @@ static void stli_start(struct tty_struct *tty)
 
 static void stli_dohangup(void *arg)
 {
-       stliport_t      *portp;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_dohangup(portp=%x)\n", (int) arg);
-#endif
-
-       /*
-        * FIXME: There's a module removal race here: tty_hangup
-        * calls schedule_work which will call into this
-        * driver later.
-        */
-       portp = (stliport_t *) arg;
-       if (portp != (stliport_t *) NULL) {
-               if (portp->tty != (struct tty_struct *) NULL) {
-                       tty_hangup(portp->tty);
-               }
+       stliport_t *portp = (stliport_t *) arg;
+       if (portp->tty != NULL) {
+               tty_hangup(portp->tty);
        }
 }
 
@@ -2254,31 +2033,25 @@ static void stli_dohangup(void *arg)
 
 static void stli_hangup(struct tty_struct *tty)
 {
-       stliport_t      *portp;
-       stlibrd_t       *brdp;
-       unsigned long   flags;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_hangup(tty=%x)\n", (int) tty);
-#endif
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned long flags;
 
-       if (tty == (struct tty_struct *) NULL)
-               return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
        portp->flags &= ~ASYNC_INITIALIZED;
 
-       save_flags(flags);
-       cli();
-       if (! test_bit(ST_CLOSING, &portp->state))
+       if (!test_bit(ST_CLOSING, &portp->state))
                stli_rawclose(brdp, portp, 0, 0);
+
+       spin_lock_irqsave(&stli_lock, flags);
        if (tty->termios->c_cflag & HUPCL) {
                stli_mkasysigs(&portp->asig, 0, 0);
                if (test_bit(ST_CMDING, &portp->state)) {
@@ -2290,14 +2063,15 @@ static void stli_hangup(struct tty_struct *tty)
                                &portp->asig, sizeof(asysigs_t), 0);
                }
        }
-       restore_flags(flags);
 
        clear_bit(ST_TXBUSY, &portp->state);
        clear_bit(ST_RXSTOP, &portp->state);
        set_bit(TTY_IO_ERROR, &tty->flags);
-       portp->tty = (struct tty_struct *) NULL;
+       portp->tty = NULL;
        portp->flags &= ~ASYNC_NORMAL_ACTIVE;
        portp->refcount = 0;
+       spin_unlock_irqrestore(&stli_lock, flags);
+
        wake_up_interruptible(&portp->open_wait);
 }
 
@@ -2312,29 +2086,22 @@ static void stli_hangup(struct tty_struct *tty)
 
 static void stli_flushbuffer(struct tty_struct *tty)
 {
-       stliport_t      *portp;
-       stlibrd_t       *brdp;
-       unsigned long   ftype, flags;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_flushbuffer(tty=%x)\n", (int) tty);
-#endif
+       stliport_t *portp;
+       stlibrd_t *brdp;
+       unsigned long ftype, flags;
 
-       if (tty == (struct tty_struct *) NULL)
-               return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        if (tty == stli_txcooktty) {
-               stli_txcooktty = (struct tty_struct *) NULL;
+               stli_txcooktty = NULL;
                stli_txcooksize = 0;
                stli_txcookrealsize = 0;
        }
@@ -2346,15 +2113,10 @@ static void stli_flushbuffer(struct tty_struct *tty)
                        ftype |= FLUSHRX;
                        clear_bit(ST_DOFLUSHRX, &portp->state);
                }
-               stli_sendcmd(brdp, portp, A_FLUSH, &ftype,
-                       sizeof(unsigned long), 0);
+               __stli_sendcmd(brdp, portp, A_FLUSH, &ftype, sizeof(u32), 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);
+       spin_unlock_irqrestore(&brd_lock, flags);
+       tty_wakeup(tty);
 }
 
 /*****************************************************************************/
@@ -2364,55 +2126,31 @@ static void stli_breakctl(struct tty_struct *tty, int state)
        stlibrd_t       *brdp;
        stliport_t      *portp;
        long            arg;
-       /* long savestate, savetime; */
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_breakctl(tty=%x,state=%d)\n", (int) tty, state);
-#endif
 
-       if (tty == (struct tty_struct *) NULL)
-               return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
-/*
- *     Due to a bug in the tty send_break() code we need to preserve
- *     the current process state and timeout...
-       savetime = current->timeout;
-       savestate = current->state;
- */
-
        arg = (state == -1) ? BREAKON : BREAKOFF;
        stli_cmdwait(brdp, portp, A_BREAK, &arg, sizeof(long), 0);
-
-/*
- *
-       current->timeout = savetime;
-       current->state = savestate;
- */
 }
 
 /*****************************************************************************/
 
 static void stli_waituntilsent(struct tty_struct *tty, int timeout)
 {
-       stliport_t      *portp;
-       unsigned long   tend;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_waituntilsent(tty=%x,timeout=%x)\n", (int) tty, timeout);
-#endif
+       stliport_t *portp;
+       unsigned long tend;
 
-       if (tty == (struct tty_struct *) NULL)
+       if (tty == NULL)
                return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
 
        if (timeout == 0)
@@ -2436,19 +2174,13 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
        stliport_t      *portp;
        asyctrl_t       actrl;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch);
-#endif
-
-       if (tty == (struct tty_struct *) NULL)
-               return;
        portp = tty->driver_data;
-       if (portp == (stliport_t *) NULL)
+       if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
+       if (brdp == NULL)
                return;
 
        memset(&actrl, 0, sizeof(asyctrl_t));
@@ -2460,7 +2192,6 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
                actrl.txctrl = CT_SENDCHR;
                actrl.tximdch = ch;
        }
-
        stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
 }
 
@@ -2476,17 +2207,17 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
 
 static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *pos)
 {
-       char    *sp, *uart;
-       int     rc, cnt;
+       char *sp, *uart;
+       int rc, cnt;
 
        rc = stli_portcmdstats(portp);
 
        uart = "UNKNOWN";
        if (brdp->state & BST_STARTED) {
                switch (stli_comstats.hwid) {
-               case 0:         uart = "2681"; break;
-               case 1:         uart = "SC26198"; break;
-               default:        uart = "CD1400"; break;
+               case 0: uart = "2681"; break;
+               case 1: uart = "SC26198"; break;
+               default:uart = "CD1400"; break;
                }
        }
 
@@ -2537,17 +2268,11 @@ static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *p
 
 static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-       stlibrd_t       *brdp;
-       stliport_t      *portp;
-       int             brdnr, portnr, totalport;
-       int             curoff, maxoff;
-       char            *pos;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x,"
-               "data=%x\n", (int) page, (int) start, (int) off, count,
-               (int) eof, (int) data);
-#endif
+       stlibrd_t *brdp;
+       stliport_t *portp;
+       int brdnr, portnr, totalport;
+       int curoff, maxoff;
+       char *pos;
 
        pos = page;
        totalport = 0;
@@ -2568,7 +2293,7 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo
  */
        for (brdnr = 0; (brdnr < stli_nrbrds); brdnr++) {
                brdp = stli_brds[brdnr];
-               if (brdp == (stlibrd_t *) NULL)
+               if (brdp == NULL)
                        continue;
                if (brdp->state == 0)
                        continue;
@@ -2583,7 +2308,7 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo
                for (portnr = 0; (portnr < brdp->nrports); portnr++,
                    totalport++) {
                        portp = brdp->ports[portnr];
-                       if (portp == (stliport_t *) NULL)
+                       if (portp == NULL)
                                continue;
                        if (off >= (curoff += MAXLINE))
                                continue;
@@ -2610,49 +2335,54 @@ stli_readdone:
  *     a poll routine that does not have user context. Therefore you cannot
  *     copy back directly into user space, or to the kernel stack of a
  *     process. This routine does not sleep, so can be called from anywhere.
+ *
+ *     The caller must hold the brd_lock (see also stli_sendcmd the usual
+ *     entry point)
  */
 
-static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
 {
-       volatile cdkhdr_t       *hdrp;
-       volatile cdkctrl_t      *cp;
-       volatile unsigned char  *bits;
-       unsigned long           flags;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_sendcmd(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,"
-               "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd,
-               (int) arg, size, copyback);
-#endif
+       cdkhdr_t __iomem *hdrp;
+       cdkctrl_t __iomem *cp;
+       unsigned char __iomem *bits;
+       unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
 
        if (test_bit(ST_CMDING, &portp->state)) {
                printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n",
                                (int) cmd);
-               restore_flags(flags);
+               spin_unlock_irqrestore(&brd_lock, flags);
                return;
        }
 
        EBRDENABLE(brdp);
-       cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
+       cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
        if (size > 0) {
-               memcpy((void *) &(cp->args[0]), arg, size);
+               memcpy_toio((void __iomem *) &(cp->args[0]), arg, size);
                if (copyback) {
                        portp->argp = arg;
                        portp->argsize = size;
                }
        }
-       cp->status = 0;
-       cp->cmd = cmd;
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+       writel(0, &cp->status);
+       writel(cmd, &cp->cmd);
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
                portp->portidx;
-       *bits |= portp->portbit;
+       writeb(readb(bits) | portp->portbit, bits);
        set_bit(ST_CMDING, &portp->state);
        EBRDDISABLE(brdp);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
+}
+
+static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+{
+       unsigned long           flags;
+
+       spin_lock_irqsave(&brd_lock, flags);
+       __stli_sendcmd(brdp, portp, cmd, arg, size, copyback);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -2667,28 +2397,23 @@ static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd,
 
 static void stli_read(stlibrd_t *brdp, stliport_t *portp)
 {
-       volatile cdkasyrq_t     *rp;
-       volatile char           *shbuf;
-       struct tty_struct       *tty;
-       unsigned int            head, tail, size;
-       unsigned int            len, stlen;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_read(brdp=%x,portp=%d)\n",
-                       (int) brdp, (int) portp);
-#endif
+       cdkasyrq_t __iomem *rp;
+       char __iomem *shbuf;
+       struct tty_struct       *tty;
+       unsigned int head, tail, size;
+       unsigned int len, stlen;
 
        if (test_bit(ST_RXSTOP, &portp->state))
                return;
        tty = portp->tty;
-       if (tty == (struct tty_struct *) NULL)
+       if (tty == NULL)
                return;
 
-       rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
-       head = (unsigned int) rp->head;
-       if (head != ((unsigned int) rp->head))
-               head = (unsigned int) rp->head;
-       tail = (unsigned int) rp->tail;
+       rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
+       head = (unsigned int) readw(&rp->head);
+       if (head != ((unsigned int) readw(&rp->head)))
+               head = (unsigned int) readw(&rp->head);
+       tail = (unsigned int) readw(&rp->tail);
        size = portp->rxsize;
        if (head >= tail) {
                len = head - tail;
@@ -2699,12 +2424,15 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
        }
 
        len = tty_buffer_request_room(tty, len);
-       /* FIXME : iomap ? */
-       shbuf = (volatile char *) EBRDGETMEMPTR(brdp, portp->rxoffset);
+
+       shbuf = (char __iomem *) EBRDGETMEMPTR(brdp, portp->rxoffset);
 
        while (len > 0) {
+               unsigned char *cptr;
+
                stlen = MIN(len, stlen);
-               tty_insert_flip_string(tty, (char *)(shbuf + tail), stlen);
+               tty_prepare_flip_string(tty, &cptr, stlen);
+               memcpy_fromio(cptr, shbuf + tail, stlen);
                len -= stlen;
                tail += stlen;
                if (tail >= size) {
@@ -2712,8 +2440,8 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
                        stlen = head;
                }
        }
-       rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
-       rp->tail = tail;
+       rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
+       writew(tail, &rp->tail);
 
        if (head != tail)
                set_bit(ST_RXING, &portp->state);
@@ -2729,9 +2457,9 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
  *     difficult to deal with them here.
  */
 
-static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
+static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp)
 {
-       int     cmd;
+       int cmd;
 
        if (test_bit(ST_DOSIGS, &portp->state)) {
                if (test_bit(ST_DOFLUSHTX, &portp->state) &&
@@ -2746,10 +2474,10 @@ static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
                clear_bit(ST_DOFLUSHTX, &portp->state);
                clear_bit(ST_DOFLUSHRX, &portp->state);
                clear_bit(ST_DOSIGS, &portp->state);
-               memcpy((void *) &(cp->args[0]), (void *) &portp->asig,
+               memcpy_toio((void __iomem *) &(cp->args[0]), (void *) &portp->asig,
                        sizeof(asysigs_t));
-               cp->status = 0;
-               cp->cmd = cmd;
+               writel(0, &cp->status);
+               writel(cmd, &cp->cmd);
                set_bit(ST_CMDING, &portp->state);
        } else if (test_bit(ST_DOFLUSHTX, &portp->state) ||
            test_bit(ST_DOFLUSHRX, &portp->state)) {
@@ -2757,9 +2485,9 @@ static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
                cmd |= ((test_bit(ST_DOFLUSHRX, &portp->state)) ? FLUSHRX : 0);
                clear_bit(ST_DOFLUSHTX, &portp->state);
                clear_bit(ST_DOFLUSHRX, &portp->state);
-               memcpy((void *) &(cp->args[0]), (void *) &cmd, sizeof(int));
-               cp->status = 0;
-               cp->cmd = A_FLUSH;
+               memcpy_toio((void __iomem *) &(cp->args[0]), (void *) &cmd, sizeof(int));
+               writel(0, &cp->status);
+               writel(A_FLUSH, &cp->cmd);
                set_bit(ST_CMDING, &portp->state);
        }
 }
@@ -2779,30 +2507,25 @@ static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
 
 static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
 {
-       volatile cdkasy_t       *ap;
-       volatile cdkctrl_t      *cp;
-       struct tty_struct       *tty;
-       asynotify_t             nt;
-       unsigned long           oldsigs;
-       int                     rc, donerx;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_hostcmd(brdp=%x,channr=%d)\n",
-                       (int) brdp, channr);
-#endif
-
-       ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
+       cdkasy_t __iomem *ap;
+       cdkctrl_t __iomem *cp;
+       struct tty_struct *tty;
+       asynotify_t nt;
+       unsigned long oldsigs;
+       int rc, donerx;
+
+       ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
        cp = &ap->ctrl;
 
 /*
  *     Check if we are waiting for an open completion message.
  */
        if (test_bit(ST_OPENING, &portp->state)) {
-               rc = (int) cp->openarg;
-               if ((cp->open == 0) && (rc != 0)) {
+               rc = readl(&cp->openarg);
+               if (readb(&cp->open) == 0 && rc != 0) {
                        if (rc > 0)
                                rc--;
-                       cp->openarg = 0;
+                       writel(0, &cp->openarg);
                        portp->rc = rc;
                        clear_bit(ST_OPENING, &portp->state);
                        wake_up_interruptible(&portp->raw_wait);
@@ -2813,11 +2536,11 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
  *     Check if we are waiting for a close completion message.
  */
        if (test_bit(ST_CLOSING, &portp->state)) {
-               rc = (int) cp->closearg;
-               if ((cp->close == 0) && (rc != 0)) {
+               rc = (int) readl(&cp->closearg);
+               if (readb(&cp->close) == 0 && rc != 0) {
                        if (rc > 0)
                                rc--;
-                       cp->closearg = 0;
+                       writel(0, &cp->closearg);
                        portp->rc = rc;
                        clear_bit(ST_CLOSING, &portp->state);
                        wake_up_interruptible(&portp->raw_wait);
@@ -2829,16 +2552,16 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
  *     need to copy out the command results associated with this command.
  */
        if (test_bit(ST_CMDING, &portp->state)) {
-               rc = cp->status;
-               if ((cp->cmd == 0) && (rc != 0)) {
+               rc = readl(&cp->status);
+               if (readl(&cp->cmd) == 0 && rc != 0) {
                        if (rc > 0)
                                rc--;
-                       if (portp->argp != (void *) NULL) {
-                               memcpy(portp->argp, (void *) &(cp->args[0]),
+                       if (portp->argp != NULL) {
+                               memcpy_fromio(portp->argp, (void __iomem *) &(cp->args[0]),
                                        portp->argsize);
-                               portp->argp = (void *) NULL;
+                               portp->argp = NULL;
                        }
-                       cp->status = 0;
+                       writel(0, &cp->status);
                        portp->rc = rc;
                        clear_bit(ST_CMDING, &portp->state);
                        stli_dodelaycmd(portp, cp);
@@ -2877,18 +2600,15 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
                if (nt.data & DT_TXEMPTY)
                        clear_bit(ST_TXBUSY, &portp->state);
                if (nt.data & (DT_TXEMPTY | DT_TXLOW)) {
-                       if (tty != (struct tty_struct *) NULL) {
-                               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                                   tty->ldisc.write_wakeup) {
-                                       (tty->ldisc.write_wakeup)(tty);
-                                       EBRDENABLE(brdp);
-                               }
+                       if (tty != NULL) {
+                               tty_wakeup(tty);
+                               EBRDENABLE(brdp);
                                wake_up_interruptible(&tty->write_wait);
                        }
                }
 
                if ((nt.data & DT_RXBREAK) && (portp->rxmarkmsk & BRKINT)) {
-                       if (tty != (struct tty_struct *) NULL) {
+                       if (tty != NULL) {
                                tty_insert_flip_char(tty, 0, TTY_BREAK);
                                if (portp->flags & ASYNC_SAK) {
                                        do_SAK(tty);
@@ -2932,14 +2652,14 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
  *     at the cdk header structure.
  */
 
-static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
+static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp)
 {
-       stliport_t      *portp;
-       unsigned char   hostbits[(STL_MAXCHANS / 8) + 1];
-       unsigned char   slavebits[(STL_MAXCHANS / 8) + 1];
-       unsigned char   *slavep;
-       int             bitpos, bitat, bitsize;
-       int             channr, nrdevs, slavebitchange;
+       stliport_t *portp;
+       unsigned char hostbits[(STL_MAXCHANS / 8) + 1];
+       unsigned char slavebits[(STL_MAXCHANS / 8) + 1];
+       unsigned char __iomem *slavep;
+       int bitpos, bitat, bitsize;
+       int channr, nrdevs, slavebitchange;
 
        bitsize = brdp->bitsize;
        nrdevs = brdp->nrdevs;
@@ -2951,7 +2671,7 @@ static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
  *     8 service bits at a time in the inner loop, so we can bypass
  *     the lot if none of them want service.
  */
-       memcpy(&hostbits[0], (((unsigned char *) hdrp) + brdp->hostoffset),
+       memcpy_fromio(&hostbits[0], (((unsigned char __iomem *) hdrp) + brdp->hostoffset),
                bitsize);
 
        memset(&slavebits[0], 0, bitsize);
@@ -2978,11 +2698,11 @@ static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
  *     service may initiate more slave requests.
  */
        if (slavebitchange) {
-               hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-               slavep = ((unsigned char *) hdrp) + brdp->slaveoffset;
+               hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+               slavep = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset;
                for (bitpos = 0; (bitpos < bitsize); bitpos++) {
-                       if (slavebits[bitpos])
-                               slavep[bitpos] &= ~slavebits[bitpos];
+                       if (readb(slavebits + bitpos))
+                               writeb(readb(slavep + bitpos) & ~slavebits[bitpos], slavebits + bitpos);
                }
        }
 }
@@ -3000,9 +2720,9 @@ static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
 
 static void stli_poll(unsigned long arg)
 {
-       volatile cdkhdr_t       *hdrp;
-       stlibrd_t               *brdp;
-       int                     brdnr;
+       cdkhdr_t __iomem *hdrp;
+       stlibrd_t *brdp;
+       int brdnr;
 
        stli_timerlist.expires = STLI_TIMEOUT;
        add_timer(&stli_timerlist);
@@ -3012,16 +2732,18 @@ static void stli_poll(unsigned long arg)
  */
        for (brdnr = 0; (brdnr < stli_nrbrds); brdnr++) {
                brdp = stli_brds[brdnr];
-               if (brdp == (stlibrd_t *) NULL)
+               if (brdp == NULL)
                        continue;
                if ((brdp->state & BST_STARTED) == 0)
                        continue;
 
+               spin_lock(&brd_lock);
                EBRDENABLE(brdp);
-               hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-               if (hdrp->hostreq)
+               hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+               if (readb(&hdrp->hostreq))
                        stli_brdpoll(brdp, hdrp);
                EBRDDISABLE(brdp);
+               spin_unlock(&brd_lock);
        }
 }
 
@@ -3034,11 +2756,6 @@ static void stli_poll(unsigned long arg)
 
 static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp)
 {
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_mkasyport(portp=%x,pp=%x,tiosp=%d)\n",
-               (int) portp, (int) pp, (int) tiosp);
-#endif
-
        memset(pp, 0, sizeof(asyport_t));
 
 /*
@@ -3157,11 +2874,6 @@ static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tio
 
 static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts)
 {
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_mkasysigs(sp=%x,dtr=%d,rts=%d)\n",
-                       (int) sp, dtr, rts);
-#endif
-
        memset(sp, 0, sizeof(asysigs_t));
        if (dtr >= 0) {
                sp->signal |= SG_DTR;
@@ -3182,13 +2894,7 @@ static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts)
 
 static long stli_mktiocm(unsigned long sigvalue)
 {
-       long    tiocm;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_mktiocm(sigvalue=%x)\n", (int) sigvalue);
-#endif
-
-       tiocm = 0;
+       long    tiocm = 0;
        tiocm |= ((sigvalue & SG_DCD) ? TIOCM_CD : 0);
        tiocm |= ((sigvalue & SG_CTS) ? TIOCM_CTS : 0);
        tiocm |= ((sigvalue & SG_RI) ? TIOCM_RI : 0);
@@ -3210,10 +2916,6 @@ static int stli_initports(stlibrd_t *brdp)
        stliport_t      *portp;
        int             i, panelnr, panelport;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_initports(brdp=%x)\n", (int) brdp);
-#endif
-
        for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) {
                portp = kzalloc(sizeof(stliport_t), GFP_KERNEL);
                if (!portp) {
@@ -3240,7 +2942,7 @@ static int stli_initports(stlibrd_t *brdp)
                brdp->ports[i] = portp;
        }
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -3253,10 +2955,6 @@ static void stli_ecpinit(stlibrd_t *brdp)
 {
        unsigned long   memconf;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpinit(brdp=%d)\n", (int) brdp);
-#endif
-
        outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR));
        udelay(10);
        outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
@@ -3270,9 +2968,6 @@ static void stli_ecpinit(stlibrd_t *brdp)
 
 static void stli_ecpenable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpenable(brdp=%x)\n", (int) brdp);
-#endif
        outb(ECP_ATENABLE, (brdp->iobase + ECP_ATCONFR));
 }
 
@@ -3280,9 +2975,6 @@ static void stli_ecpenable(stlibrd_t *brdp)
 
 static void stli_ecpdisable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpdisable(brdp=%x)\n", (int) brdp);
-#endif
        outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
 }
 
@@ -3290,13 +2982,8 @@ static void stli_ecpdisable(stlibrd_t *brdp)
 
 static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
-       void            *ptr;
-       unsigned char   val;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
-               (int) offset);
-#endif
+       void *ptr;
+       unsigned char val;
 
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
@@ -3316,10 +3003,6 @@ static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 
 static void stli_ecpreset(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpreset(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR));
        udelay(10);
        outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
@@ -3330,9 +3013,6 @@ static void stli_ecpreset(stlibrd_t *brdp)
 
 static void stli_ecpintr(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpintr(brdp=%x)\n", (int) brdp);
-#endif
        outb(0x1, brdp->iobase);
 }
 
@@ -3346,10 +3026,6 @@ static void stli_ecpeiinit(stlibrd_t *brdp)
 {
        unsigned long   memconf;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpeiinit(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(0x1, (brdp->iobase + ECP_EIBRDENAB));
        outb(ECP_EISTOP, (brdp->iobase + ECP_EICONFR));
        udelay(10);
@@ -3383,11 +3059,6 @@ static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line
        void            *ptr;
        unsigned char   val;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecpeigetmemptr(brdp=%x,offset=%x,line=%d)\n",
-               (int) brdp, (int) offset, line);
-#endif
-
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
                                "range at line=%d(%d), brd=%d\n",
@@ -3437,8 +3108,8 @@ static void stli_ecpmcdisable(stlibrd_t *brdp)
 
 static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
-       void            *ptr;
-       unsigned char   val;
+       void *ptr;
+       unsigned char val;
 
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
@@ -3472,10 +3143,6 @@ static void stli_ecpmcreset(stlibrd_t *brdp)
 
 static void stli_ecppciinit(stlibrd_t *brdp)
 {
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecppciinit(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR));
        udelay(10);
        outb(0, (brdp->iobase + ECP_PCICONFR));
@@ -3489,11 +3156,6 @@ static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int lin
        void            *ptr;
        unsigned char   val;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_ecppcigetmemptr(brdp=%x,offset=%x,line=%d)\n",
-               (int) brdp, (int) offset, line);
-#endif
-
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
                                "range at line=%d(%d), board=%d\n",
@@ -3528,10 +3190,6 @@ static void stli_onbinit(stlibrd_t *brdp)
 {
        unsigned long   memconf;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbinit(brdp=%d)\n", (int) brdp);
-#endif
-
        outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
        udelay(10);
        outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
@@ -3547,9 +3205,6 @@ static void stli_onbinit(stlibrd_t *brdp)
 
 static void stli_onbenable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbenable(brdp=%x)\n", (int) brdp);
-#endif
        outb((brdp->enabval | ONB_ATENABLE), (brdp->iobase + ONB_ATCONFR));
 }
 
@@ -3557,9 +3212,6 @@ static void stli_onbenable(stlibrd_t *brdp)
 
 static void stli_onbdisable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbdisable(brdp=%x)\n", (int) brdp);
-#endif
        outb((brdp->enabval | ONB_ATDISABLE), (brdp->iobase + ONB_ATCONFR));
 }
 
@@ -3569,11 +3221,6 @@ static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
        void    *ptr;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
-               (int) offset);
-#endif
-
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
                                "range at line=%d(%d), brd=%d\n",
@@ -3589,11 +3236,6 @@ static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 
 static void stli_onbreset(stlibrd_t *brdp)
 {      
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbreset(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
        udelay(10);
        outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
@@ -3610,10 +3252,6 @@ static void stli_onbeinit(stlibrd_t *brdp)
 {
        unsigned long   memconf;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbeinit(brdp=%d)\n", (int) brdp);
-#endif
-
        outb(0x1, (brdp->iobase + ONB_EIBRDENAB));
        outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
        udelay(10);
@@ -3632,9 +3270,6 @@ static void stli_onbeinit(stlibrd_t *brdp)
 
 static void stli_onbeenable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbeenable(brdp=%x)\n", (int) brdp);
-#endif
        outb(ONB_EIENABLE, (brdp->iobase + ONB_EICONFR));
 }
 
@@ -3642,9 +3277,6 @@ static void stli_onbeenable(stlibrd_t *brdp)
 
 static void stli_onbedisable(stlibrd_t *brdp)
 {      
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbedisable(brdp=%x)\n", (int) brdp);
-#endif
        outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
 }
 
@@ -3652,13 +3284,8 @@ static void stli_onbedisable(stlibrd_t *brdp)
 
 static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
-       void            *ptr;
-       unsigned char   val;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_onbegetmemptr(brdp=%x,offset=%x,line=%d)\n",
-               (int) brdp, (int) offset, line);
-#endif
+       void *ptr;
+       unsigned char val;
 
        if (offset > brdp->memsize) {
                printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
@@ -3681,11 +3308,6 @@ static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 
 static void stli_onbereset(stlibrd_t *brdp)
 {      
-
-#ifdef DEBUG
-       printk(KERN_ERR "stli_onbereset(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
        udelay(10);
        outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
@@ -3700,11 +3322,6 @@ static void stli_onbereset(stlibrd_t *brdp)
 
 static void stli_bbyinit(stlibrd_t *brdp)
 {
-
-#ifdef DEBUG
-       printk(KERN_ERR "stli_bbyinit(brdp=%d)\n", (int) brdp);
-#endif
-
        outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
        udelay(10);
        outb(0, (brdp->iobase + BBY_ATCONFR));
@@ -3717,24 +3334,13 @@ static void stli_bbyinit(stlibrd_t *brdp)
 
 static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
-       void            *ptr;
-       unsigned char   val;
+       void *ptr;
+       unsigned char val;
 
-#ifdef DEBUG
-       printk(KERN_ERR "stli_bbygetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
-               (int) offset);
-#endif
+       BUG_ON(offset > brdp->memsize);
 
-       if (offset > brdp->memsize) {
-               printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
-                               "range at line=%d(%d), brd=%d\n",
-                               (int) offset, line, __LINE__, brdp->brdnr);
-               ptr = NULL;
-               val = 0;
-       } else {
-               ptr = brdp->membase + (offset % BBY_PAGESIZE);
-               val = (unsigned char) (offset / BBY_PAGESIZE);
-       }
+       ptr = brdp->membase + (offset % BBY_PAGESIZE);
+       val = (unsigned char) (offset / BBY_PAGESIZE);
        outb(val, (brdp->iobase + BBY_ATCONFR));
        return(ptr);
 }
@@ -3743,11 +3349,6 @@ static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 
 static void stli_bbyreset(stlibrd_t *brdp)
 {      
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_bbyreset(brdp=%x)\n", (int) brdp);
-#endif
-
        outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
        udelay(10);
        outb(0, (brdp->iobase + BBY_ATCONFR));
@@ -3762,11 +3363,6 @@ static void stli_bbyreset(stlibrd_t *brdp)
 
 static void stli_stalinit(stlibrd_t *brdp)
 {
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_stalinit(brdp=%d)\n", (int) brdp);
-#endif
-
        outb(0x1, brdp->iobase);
        mdelay(1000);
 }
@@ -3775,36 +3371,18 @@ static void stli_stalinit(stlibrd_t *brdp)
 
 static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
 {      
-       void    *ptr;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_stalgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
-               (int) offset);
-#endif
-
-       if (offset > brdp->memsize) {
-               printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
-                               "range at line=%d(%d), brd=%d\n",
-                               (int) offset, line, __LINE__, brdp->brdnr);
-               ptr = NULL;
-       } else {
-               ptr = brdp->membase + (offset % STAL_PAGESIZE);
-       }
-       return(ptr);
+       BUG_ON(offset > brdp->memsize);
+       return brdp->membase + (offset % STAL_PAGESIZE);
 }
 
 /*****************************************************************************/
 
 static void stli_stalreset(stlibrd_t *brdp)
 {      
-       volatile unsigned long  *vecp;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_stalreset(brdp=%x)\n", (int) brdp);
-#endif
+       u32 __iomem *vecp;
 
-       vecp = (volatile unsigned long *) (brdp->membase + 0x30);
-       *vecp = 0xffff0000;
+       vecp = (u32 __iomem *) (brdp->membase + 0x30);
+       writel(0xffff0000, vecp);
        outb(0, brdp->iobase);
        mdelay(1000);
 }
@@ -3818,15 +3396,11 @@ static void stli_stalreset(stlibrd_t *brdp)
 
 static int stli_initecp(stlibrd_t *brdp)
 {
-       cdkecpsig_t     sig;
-       cdkecpsig_t     *sigsp;
-       unsigned int    status, nxtid;
-       char            *name;
-       int             panelnr, nrports;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_initecp(brdp=%x)\n", (int) brdp);
-#endif
+       cdkecpsig_t sig;
+       cdkecpsig_t __iomem *sigsp;
+       unsigned int status, nxtid;
+       char *name;
+       int panelnr, nrports;
 
        if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
                return -EIO;
@@ -3834,7 +3408,7 @@ static int stli_initecp(stlibrd_t *brdp)
        if ((brdp->iobase == 0) || (brdp->memaddr == 0))
        {
                release_region(brdp->iobase, brdp->iosize);
-               return(-ENODEV);
+               return -ENODEV;
        }
 
        brdp->iosize = ECP_IOSIZE;
@@ -3903,7 +3477,7 @@ static int stli_initecp(stlibrd_t *brdp)
 
        default:
                release_region(brdp->iobase, brdp->iosize);
-               return(-EINVAL);
+               return -EINVAL;
        }
 
 /*
@@ -3915,10 +3489,10 @@ static int stli_initecp(stlibrd_t *brdp)
        EBRDINIT(brdp);
 
        brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
-       if (brdp->membase == (void *) NULL)
+       if (brdp->membase == NULL)
        {
                release_region(brdp->iobase, brdp->iosize);
-               return(-ENOMEM);
+               return -ENOMEM;
        }
 
 /*
@@ -3927,23 +3501,14 @@ static int stli_initecp(stlibrd_t *brdp)
  *     this is, and what it is connected to it.
  */
        EBRDENABLE(brdp);
-       sigsp = (cdkecpsig_t *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
+       sigsp = (cdkecpsig_t __iomem *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
        memcpy(&sig, sigsp, sizeof(cdkecpsig_t));
        EBRDDISABLE(brdp);
 
-#if 0
-       printk("%s(%d): sig-> magic=%x rom=%x panel=%x,%x,%x,%x,%x,%x,%x,%x\n",
-               __FILE__, __LINE__, (int) sig.magic, sig.romver, sig.panelid[0],
-               (int) sig.panelid[1], (int) sig.panelid[2],
-               (int) sig.panelid[3], (int) sig.panelid[4],
-               (int) sig.panelid[5], (int) sig.panelid[6],
-               (int) sig.panelid[7]);
-#endif
-
-       if (sig.magic != ECP_MAGIC)
+       if (sig.magic != cpu_to_le32(ECP_MAGIC))
        {
                release_region(brdp->iobase, brdp->iosize);
-               return(-ENODEV);
+               return -ENODEV;
        }
 
 /*
@@ -3967,7 +3532,7 @@ static int stli_initecp(stlibrd_t *brdp)
 
 
        brdp->state |= BST_FOUND;
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -3979,20 +3544,16 @@ static int stli_initecp(stlibrd_t *brdp)
 
 static int stli_initonb(stlibrd_t *brdp)
 {
-       cdkonbsig_t     sig;
-       cdkonbsig_t     *sigsp;
-       char            *name;
-       int             i;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_initonb(brdp=%x)\n", (int) brdp);
-#endif
+       cdkonbsig_t sig;
+       cdkonbsig_t __iomem *sigsp;
+       char *name;
+       int i;
 
 /*
  *     Do a basic sanity check on the IO and memory addresses.
  */
-       if ((brdp->iobase == 0) || (brdp->memaddr == 0))
-               return(-ENODEV);
+       if (brdp->iobase == 0 || brdp->memaddr == 0)
+               return -ENODEV;
 
        brdp->iosize = ONB_IOSIZE;
        
@@ -4010,7 +3571,6 @@ static int stli_initonb(stlibrd_t *brdp)
        case BRD_ONBOARD2:
        case BRD_ONBOARD2_32:
        case BRD_ONBOARDRS:
-               brdp->membase = (void *) brdp->memaddr;
                brdp->memsize = ONB_MEMSIZE;
                brdp->pagesize = ONB_ATPAGESIZE;
                brdp->init = stli_onbinit;
@@ -4028,7 +3588,6 @@ static int stli_initonb(stlibrd_t *brdp)
                break;
 
        case BRD_ONBOARDE:
-               brdp->membase = (void *) brdp->memaddr;
                brdp->memsize = ONB_EIMEMSIZE;
                brdp->pagesize = ONB_EIPAGESIZE;
                brdp->init = stli_onbeinit;
@@ -4044,7 +3603,6 @@ static int stli_initonb(stlibrd_t *brdp)
        case BRD_BRUMBY4:
        case BRD_BRUMBY8:
        case BRD_BRUMBY16:
-               brdp->membase = (void *) brdp->memaddr;
                brdp->memsize = BBY_MEMSIZE;
                brdp->pagesize = BBY_PAGESIZE;
                brdp->init = stli_bbyinit;
@@ -4058,7 +3616,6 @@ static int stli_initonb(stlibrd_t *brdp)
                break;
 
        case BRD_STALLION:
-               brdp->membase = (void *) brdp->memaddr;
                brdp->memsize = STAL_MEMSIZE;
                brdp->pagesize = STAL_PAGESIZE;
                brdp->init = stli_stalinit;
@@ -4073,7 +3630,7 @@ static int stli_initonb(stlibrd_t *brdp)
 
        default:
                release_region(brdp->iobase, brdp->iosize);
-               return(-EINVAL);
+               return -EINVAL;
        }
 
 /*
@@ -4085,10 +3642,10 @@ static int stli_initonb(stlibrd_t *brdp)
        EBRDINIT(brdp);
 
        brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
-       if (brdp->membase == (void *) NULL)
+       if (brdp->membase == NULL)
        {
                release_region(brdp->iobase, brdp->iosize);
-               return(-ENOMEM);
+               return -ENOMEM;
        }
 
 /*
@@ -4097,21 +3654,17 @@ static int stli_initonb(stlibrd_t *brdp)
  *     this is, and how many ports.
  */
        EBRDENABLE(brdp);
-       sigsp = (cdkonbsig_t *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
-       memcpy(&sig, sigsp, sizeof(cdkonbsig_t));
+       sigsp = (cdkonbsig_t __iomem *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
+       memcpy_fromio(&sig, sigsp, sizeof(cdkonbsig_t));
        EBRDDISABLE(brdp);
 
-#if 0
-       printk("%s(%d): sig-> magic=%x:%x:%x:%x romver=%x amask=%x:%x:%x\n",
-               __FILE__, __LINE__, sig.magic0, sig.magic1, sig.magic2,
-               sig.magic3, sig.romver, sig.amask0, sig.amask1, sig.amask2);
-#endif
-
-       if ((sig.magic0 != ONB_MAGIC0) || (sig.magic1 != ONB_MAGIC1) ||
-           (sig.magic2 != ONB_MAGIC2) || (sig.magic3 != ONB_MAGIC3))
+       if (sig.magic0 != cpu_to_le16(ONB_MAGIC0) ||
+           sig.magic1 != cpu_to_le16(ONB_MAGIC1) ||
+           sig.magic2 != cpu_to_le16(ONB_MAGIC2) ||
+           sig.magic3 != cpu_to_le16(ONB_MAGIC3))
        {
                release_region(brdp->iobase, brdp->iosize);
-               return(-ENODEV);
+               return -ENODEV;
        }
 
 /*
@@ -4132,7 +3685,7 @@ static int stli_initonb(stlibrd_t *brdp)
 
 
        brdp->state |= BST_FOUND;
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4145,31 +3698,25 @@ static int stli_initonb(stlibrd_t *brdp)
 
 static int stli_startbrd(stlibrd_t *brdp)
 {
-       volatile cdkhdr_t       *hdrp;
-       volatile cdkmem_t       *memp;
-       volatile cdkasy_t       *ap;
-       unsigned long           flags;
-       stliport_t              *portp;
-       int                     portnr, nrdevs, i, rc;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_startbrd(brdp=%x)\n", (int) brdp);
-#endif
-
-       rc = 0;
-
-       save_flags(flags);
-       cli();
+       cdkhdr_t __iomem *hdrp;
+       cdkmem_t __iomem *memp;
+       cdkasy_t __iomem *ap;
+       unsigned long flags;
+       stliport_t *portp;
+       int portnr, nrdevs, i, rc = 0;
+       u32 memoff;
+
+       spin_lock_irqsave(&brd_lock, flags);
        EBRDENABLE(brdp);
-       hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+       hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
        nrdevs = hdrp->nrdevs;
 
 #if 0
        printk("%s(%d): CDK version %d.%d.%d --> "
                "nrdevs=%d memp=%x hostp=%x slavep=%x\n",
-                __FILE__, __LINE__, hdrp->ver_release, hdrp->ver_modification,
-                hdrp->ver_fix, nrdevs, (int) hdrp->memp, (int) hdrp->hostp,
-                (int) hdrp->slavep);
+                __FILE__, __LINE__, readb(&hdrp->ver_release), readb(&hdrp->ver_modification),
+                readb(&hdrp->ver_fix), nrdevs, (int) readl(&hdrp->memp), readl(&hdrp->hostp),
+                readl(&hdrp->slavep));
 #endif
 
        if (nrdevs < (brdp->nrports + 1)) {
@@ -4181,14 +3728,14 @@ static int stli_startbrd(stlibrd_t *brdp)
        brdp->hostoffset = hdrp->hostp - CDK_CDKADDR;
        brdp->slaveoffset = hdrp->slavep - CDK_CDKADDR;
        brdp->bitsize = (nrdevs + 7) / 8;
-       memp = (volatile cdkmem_t *) hdrp->memp;
-       if (((unsigned long) memp) > brdp->memsize) {
+       memoff = readl(&hdrp->memp);
+       if (memoff > brdp->memsize) {
                printk(KERN_ERR "STALLION: corrupted shared memory region?\n");
                rc = -EIO;
                goto stli_donestartup;
        }
-       memp = (volatile cdkmem_t *) EBRDGETMEMPTR(brdp, (unsigned long) memp);
-       if (memp->dtype != TYP_ASYNCTRL) {
+       memp = (cdkmem_t __iomem *) EBRDGETMEMPTR(brdp, memoff);
+       if (readw(&memp->dtype) != TYP_ASYNCTRL) {
                printk(KERN_ERR "STALLION: no slave control device found\n");
                goto stli_donestartup;
        }
@@ -4200,19 +3747,19 @@ static int stli_startbrd(stlibrd_t *brdp)
  *     change pages while reading memory map.
  */
        for (i = 1, portnr = 0; (i < nrdevs); i++, portnr++, memp++) {
-               if (memp->dtype != TYP_ASYNC)
+               if (readw(&memp->dtype) != TYP_ASYNC)
                        break;
                portp = brdp->ports[portnr];
-               if (portp == (stliport_t *) NULL)
+               if (portp == NULL)
                        break;
                portp->devnr = i;
-               portp->addr = memp->offset;
+               portp->addr = readl(&memp->offset);
                portp->reqbit = (unsigned char) (0x1 << (i * 8 / nrdevs));
                portp->portidx = (unsigned char) (i / 8);
                portp->portbit = (unsigned char) (0x1 << (i % 8));
        }
 
-       hdrp->slavereq = 0xff;
+       writeb(0xff, &hdrp->slavereq);
 
 /*
  *     For each port setup a local copy of the RX and TX buffer offsets
@@ -4221,22 +3768,22 @@ static int stli_startbrd(stlibrd_t *brdp)
  */
        for (i = 1, portnr = 0; (i < nrdevs); i++, portnr++) {
                portp = brdp->ports[portnr];
-               if (portp == (stliport_t *) NULL)
+               if (portp == NULL)
                        break;
                if (portp->addr == 0)
                        break;
-               ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
-               if (ap != (volatile cdkasy_t *) NULL) {
-                       portp->rxsize = ap->rxq.size;
-                       portp->txsize = ap->txq.size;
-                       portp->rxoffset = ap->rxq.offset;
-                       portp->txoffset = ap->txq.offset;
+               ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+               if (ap != NULL) {
+                       portp->rxsize = readw(&ap->rxq.size);
+                       portp->txsize = readw(&ap->txq.size);
+                       portp->rxoffset = readl(&ap->rxq.offset);
+                       portp->txoffset = readl(&ap->txq.offset);
                }
        }
 
 stli_donestartup:
        EBRDDISABLE(brdp);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        if (rc == 0)
                brdp->state |= BST_STARTED;
@@ -4247,7 +3794,7 @@ stli_donestartup:
                add_timer(&stli_timerlist);
        }
 
-       return(rc);
+       return rc;
 }
 
 /*****************************************************************************/
@@ -4258,10 +3805,6 @@ stli_donestartup:
 
 static int __init stli_brdinit(stlibrd_t *brdp)
 {
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_brdinit(brdp=%x)\n", (int) brdp);
-#endif
-
        stli_brds[brdp->brdnr] = brdp;
 
        switch (brdp->brdtype) {
@@ -4289,11 +3832,11 @@ static int __init stli_brdinit(stlibrd_t *brdp)
        case BRD_ECHPCI:
                printk(KERN_ERR "STALLION: %s board type not supported in "
                                "this driver\n", stli_brdnames[brdp->brdtype]);
-               return(ENODEV);
+               return -ENODEV;
        default:
                printk(KERN_ERR "STALLION: board=%d is unknown board "
                                "type=%d\n", brdp->brdnr, brdp->brdtype);
-               return(ENODEV);
+               return -ENODEV;
        }
 
        if ((brdp->state & BST_FOUND) == 0) {
@@ -4301,7 +3844,7 @@ static int __init stli_brdinit(stlibrd_t *brdp)
                                "io=%x mem=%x\n",
                        stli_brdnames[brdp->brdtype], brdp->brdnr,
                        brdp->iobase, (int) brdp->memaddr);
-               return(ENODEV);
+               return -ENODEV;
        }
 
        stli_initports(brdp);
@@ -4309,7 +3852,7 @@ static int __init stli_brdinit(stlibrd_t *brdp)
                "nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype],
                brdp->brdnr, brdp->iobase, (int) brdp->memaddr,
                brdp->nrpanels, brdp->nrports);
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4321,14 +3864,10 @@ static int __init stli_brdinit(stlibrd_t *brdp)
 
 static int stli_eisamemprobe(stlibrd_t *brdp)
 {
-       cdkecpsig_t     ecpsig, *ecpsigp;
-       cdkonbsig_t     onbsig, *onbsigp;
+       cdkecpsig_t     ecpsig, __iomem *ecpsigp;
+       cdkonbsig_t     onbsig, __iomem *onbsigp;
        int             i, foundit;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_eisamemprobe(brdp=%x)\n", (int) brdp);
-#endif
-
 /*
  *     First up we reset the board, to get it into a known state. There
  *     is only 2 board types here we need to worry about. Don;t use the
@@ -4352,7 +3891,7 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
                mdelay(1);
                stli_onbeenable(brdp);
        } else {
-               return(-ENODEV);
+               return -ENODEV;
        }
 
        foundit = 0;
@@ -4364,25 +3903,24 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
  */
        for (i = 0; (i < stli_eisamempsize); i++) {
                brdp->memaddr = stli_eisamemprobeaddrs[i];
-               brdp->membase = (void *) brdp->memaddr;
                brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
-               if (brdp->membase == (void *) NULL)
+               if (brdp->membase == NULL)
                        continue;
 
                if (brdp->brdtype == BRD_ECPE) {
-                       ecpsigp = (cdkecpsig_t *) stli_ecpeigetmemptr(brdp,
+                       ecpsigp = (cdkecpsig_t __iomem *) stli_ecpeigetmemptr(brdp,
                                CDK_SIGADDR, __LINE__);
-                       memcpy(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
-                       if (ecpsig.magic == ECP_MAGIC)
+                       memcpy_fromio(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
+                       if (ecpsig.magic == cpu_to_le32(ECP_MAGIC))
                                foundit = 1;
                } else {
-                       onbsigp = (cdkonbsig_t *) stli_onbegetmemptr(brdp,
+                       onbsigp = (cdkonbsig_t __iomem *) stli_onbegetmemptr(brdp,
                                CDK_SIGADDR, __LINE__);
-                       memcpy(&onbsig, onbsigp, sizeof(cdkonbsig_t));
-                       if ((onbsig.magic0 == ONB_MAGIC0) &&
-                           (onbsig.magic1 == ONB_MAGIC1) &&
-                           (onbsig.magic2 == ONB_MAGIC2) &&
-                           (onbsig.magic3 == ONB_MAGIC3))
+                       memcpy_fromio(&onbsig, onbsigp, sizeof(cdkonbsig_t));
+                       if ((onbsig.magic0 == cpu_to_le16(ONB_MAGIC0)) &&
+                           (onbsig.magic1 == cpu_to_le16(ONB_MAGIC1)) &&
+                           (onbsig.magic2 == cpu_to_le16(ONB_MAGIC2)) &&
+                           (onbsig.magic3 == cpu_to_le16(ONB_MAGIC3)))
                                foundit = 1;
                }
 
@@ -4406,9 +3944,9 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
                printk(KERN_ERR "STALLION: failed to probe shared memory "
                                "region for %s in EISA slot=%d\n",
                        stli_brdnames[brdp->brdtype], (brdp->iobase >> 12));
-               return(-ENODEV);
+               return -ENODEV;
        }
-       return(0);
+       return 0;
 }
 
 static int stli_getbrdnr(void)
@@ -4439,22 +3977,16 @@ static int stli_getbrdnr(void)
 
 static int stli_findeisabrds(void)
 {
-       stlibrd_t       *brdp;
-       unsigned int    iobase, eid;
-       int             i;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_findeisabrds()\n");
-#endif
+       stlibrd_t *brdp;
+       unsigned int iobase, eid;
+       int i;
 
 /*
- *     Firstly check if this is an EISA system. Do this by probing for
- *     the system board EISA ID. If this is not an EISA system then
+ *     Firstly check if this is an EISA system.  If this is not an EISA system then
  *     don't bother going any further!
  */
-       outb(0xff, 0xc80);
-       if (inb(0xc80) == 0xff)
-               return(0);
+       if (EISA_bus)
+               return 0;
 
 /*
  *     Looks like an EISA system, so go searching for EISA boards.
@@ -4472,7 +4004,7 @@ static int stli_findeisabrds(void)
  */
                for (i = 0; (i < STL_MAXBRDS); i++) {
                        brdp = stli_brds[i];
-                       if (brdp == (stlibrd_t *) NULL)
+                       if (brdp == NULL)
                                continue;
                        if (brdp->iobase == iobase)
                                break;
@@ -4484,10 +4016,10 @@ static int stli_findeisabrds(void)
  *             We have found a Stallion board and it is not configured already.
  *             Allocate a board structure and initialize it.
  */
-               if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
-                       return(-ENOMEM);
+               if ((brdp = stli_allocbrd()) == NULL)
+                       return -ENOMEM;
                if ((brdp->brdnr = stli_getbrdnr()) < 0)
-                       return(-ENOMEM);
+                       return -ENOMEM;
                eid = inb(iobase + 0xc82);
                if (eid == ECP_EISAID)
                        brdp->brdtype = BRD_ECPE;
@@ -4502,7 +4034,7 @@ static int stli_findeisabrds(void)
                stli_brdinit(brdp);
        }
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4523,32 +4055,18 @@ static int stli_findeisabrds(void)
 
 static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
 {
-       stlibrd_t       *brdp;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n",
-               brdtype, dev->bus->number, dev->devfn);
-#endif
+       stlibrd_t *brdp;
 
        if (pci_enable_device(devp))
-               return(-EIO);
-       if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
-               return(-ENOMEM);
+               return -EIO;
+       if ((brdp = stli_allocbrd()) == NULL)
+               return -ENOMEM;
        if ((brdp->brdnr = stli_getbrdnr()) < 0) {
                printk(KERN_INFO "STALLION: too many boards found, "
                        "maximum supported %d\n", STL_MAXBRDS);
-               return(0);
+               return 0;
        }
        brdp->brdtype = brdtype;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "%s(%d): BAR[]=%lx,%lx,%lx,%lx\n", __FILE__, __LINE__,
-               pci_resource_start(devp, 0),
-               pci_resource_start(devp, 1),
-               pci_resource_start(devp, 2),
-               pci_resource_start(devp, 3));
-#endif
-
 /*
  *     We have all resources from the board, so lets setup the actual
  *     board structure now.
@@ -4557,7 +4075,7 @@ static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
        brdp->memaddr = pci_resource_start(devp, 2);
        stli_brdinit(brdp);
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4569,20 +4087,12 @@ static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
 
 static int stli_findpcibrds(void)
 {
-       struct pci_dev  *dev = NULL;
-       int             rc;
-
-#ifdef DEBUG
-       printk("stli_findpcibrds()\n");
-#endif
+       struct pci_dev *dev = NULL;
 
-       while ((dev = pci_find_device(PCI_VENDOR_ID_STALLION,
-           PCI_DEVICE_ID_ECRA, dev))) {
-               if ((rc = stli_initpcibrd(BRD_ECPPCI, dev)))
-                       return(rc);
+       while ((dev = pci_get_device(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA, dev))) {
+               stli_initpcibrd(BRD_ECPPCI, dev);
        }
-
-       return(0);
+       return 0;
 }
 
 #endif
@@ -4595,17 +4105,16 @@ static int stli_findpcibrds(void)
 
 static stlibrd_t *stli_allocbrd(void)
 {
-       stlibrd_t       *brdp;
+       stlibrd_t *brdp;
 
        brdp = kzalloc(sizeof(stlibrd_t), GFP_KERNEL);
        if (!brdp) {
                printk(KERN_ERR "STALLION: failed to allocate memory "
-                               "(size=%d)\n", sizeof(stlibrd_t));
+                               "(size=%Zd)\n", sizeof(stlibrd_t));
                return NULL;
        }
-
        brdp->magic = STLI_BOARDMAGIC;
-       return(brdp);
+       return brdp;
 }
 
 /*****************************************************************************/
@@ -4617,13 +4126,9 @@ static stlibrd_t *stli_allocbrd(void)
 
 static int stli_initbrds(void)
 {
-       stlibrd_t       *brdp, *nxtbrdp;
-       stlconf_t       *confp;
-       int             i, j;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_initbrds()\n");
-#endif
+       stlibrd_t *brdp, *nxtbrdp;
+       stlconf_t *confp;
+       int i, j;
 
        if (stli_nrbrds > STL_MAXBRDS) {
                printk(KERN_INFO "STALLION: too many boards in configuration "
@@ -4638,11 +4143,9 @@ static int stli_initbrds(void)
  */
        for (i = 0; (i < stli_nrbrds); i++) {
                confp = &stli_brdconf[i];
-#ifdef MODULE
                stli_parsebrd(confp, stli_brdsp[i]);
-#endif
-               if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
-                       return(-ENOMEM);
+               if ((brdp = stli_allocbrd()) == NULL)
+                       return -ENOMEM;
                brdp->brdnr = i;
                brdp->brdtype = confp->brdtype;
                brdp->iobase = confp->ioaddr1;
@@ -4654,9 +4157,7 @@ static int stli_initbrds(void)
  *     Static configuration table done, so now use dynamic methods to
  *     see if any more boards should be configured.
  */
-#ifdef MODULE
        stli_argbrds();
-#endif
        if (STLI_EISAPROBE)
                stli_findeisabrds();
 #ifdef CONFIG_PCI
@@ -4672,11 +4173,11 @@ static int stli_initbrds(void)
        if (stli_nrbrds > 1) {
                for (i = 0; (i < stli_nrbrds); i++) {
                        brdp = stli_brds[i];
-                       if (brdp == (stlibrd_t *) NULL)
+                       if (brdp == NULL)
                                continue;
                        for (j = i + 1; (j < stli_nrbrds); j++) {
                                nxtbrdp = stli_brds[j];
-                               if (nxtbrdp == (stlibrd_t *) NULL)
+                               if (nxtbrdp == NULL)
                                        continue;
                                if ((brdp->membase >= nxtbrdp->membase) &&
                                    (brdp->membase <= (nxtbrdp->membase +
@@ -4691,7 +4192,7 @@ static int stli_initbrds(void)
        if (stli_shared == 0) {
                for (i = 0; (i < stli_nrbrds); i++) {
                        brdp = stli_brds[i];
-                       if (brdp == (stlibrd_t *) NULL)
+                       if (brdp == NULL)
                                continue;
                        if (brdp->state & BST_FOUND) {
                                EBRDENABLE(brdp);
@@ -4701,7 +4202,7 @@ static int stli_initbrds(void)
                }
        }
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4714,48 +4215,55 @@ static int stli_initbrds(void)
 
 static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp)
 {
-       unsigned long   flags;
-       void            *memptr;
-       stlibrd_t       *brdp;
-       int             brdnr, size, n;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_memread(fp=%x,buf=%x,count=%x,offp=%x)\n",
-                       (int) fp, (int) buf, count, (int) offp);
-#endif
+       unsigned long flags;
+       void *memptr;
+       stlibrd_t *brdp;
+       int brdnr, size, n;
+       void *p;
+       loff_t off = *offp;
 
        brdnr = iminor(fp->f_dentry->d_inode);
        if (brdnr >= stli_nrbrds)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stli_brds[brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
        if (brdp->state == 0)
-               return(-ENODEV);
-       if (fp->f_pos >= brdp->memsize)
-               return(0);
+               return -ENODEV;
+       if (off >= brdp->memsize || off + count < off)
+               return 0;
 
-       size = MIN(count, (brdp->memsize - fp->f_pos));
+       size = MIN(count, (brdp->memsize - off));
+
+       /*
+        *      Copy the data a page at a time
+        */
+
+       p = (void *)__get_free_page(GFP_KERNEL);
+       if(p == NULL)
+               return -ENOMEM;
 
-       save_flags(flags);
-       cli();
-       EBRDENABLE(brdp);
        while (size > 0) {
-               memptr = (void *) EBRDGETMEMPTR(brdp, fp->f_pos);
-               n = MIN(size, (brdp->pagesize - (((unsigned long) fp->f_pos) % brdp->pagesize)));
-               if (copy_to_user(buf, memptr, n)) {
+               spin_lock_irqsave(&brd_lock, flags);
+               EBRDENABLE(brdp);
+               memptr = (void *) EBRDGETMEMPTR(brdp, off);
+               n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+               n = MIN(n, PAGE_SIZE);
+               memcpy_fromio(p, memptr, n);
+               EBRDDISABLE(brdp);
+               spin_unlock_irqrestore(&brd_lock, flags);
+               if (copy_to_user(buf, p, n)) {
                        count = -EFAULT;
                        goto out;
                }
-               fp->f_pos += n;
+               off += n;
                buf += n;
                size -= n;
        }
 out:
-       EBRDDISABLE(brdp);
-       restore_flags(flags);
-
-       return(count);
+       *offp = off;
+       free_page((unsigned long)p);
+       return count;
 }
 
 /*****************************************************************************/
@@ -4764,54 +4272,65 @@ out:
  *     Code to handle an "staliomem" write operation. This device is the 
  *     contents of the board shared memory. It is used for down loading
  *     the slave image (and debugging :-)
+ *
+ *     FIXME: copy under lock
  */
 
 static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp)
 {
-       unsigned long   flags;
-       void            *memptr;
-       stlibrd_t       *brdp;
-       char            __user *chbuf;
-       int             brdnr, size, n;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_memwrite(fp=%x,buf=%x,count=%x,offp=%x)\n",
-                       (int) fp, (int) buf, count, (int) offp);
-#endif
+       unsigned long flags;
+       void *memptr;
+       stlibrd_t *brdp;
+       char __user *chbuf;
+       int brdnr, size, n;
+       void *p;
+       loff_t off = *offp;
 
        brdnr = iminor(fp->f_dentry->d_inode);
+
        if (brdnr >= stli_nrbrds)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stli_brds[brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
        if (brdp->state == 0)
-               return(-ENODEV);
-       if (fp->f_pos >= brdp->memsize)
-               return(0);
+               return -ENODEV;
+       if (off >= brdp->memsize || off + count < off)
+               return 0;
 
        chbuf = (char __user *) buf;
-       size = MIN(count, (brdp->memsize - fp->f_pos));
+       size = MIN(count, (brdp->memsize - off));
+
+       /*
+        *      Copy the data a page at a time
+        */
+
+       p = (void *)__get_free_page(GFP_KERNEL);
+       if(p == NULL)
+               return -ENOMEM;
 
-       save_flags(flags);
-       cli();
-       EBRDENABLE(brdp);
        while (size > 0) {
-               memptr = (void *) EBRDGETMEMPTR(brdp, fp->f_pos);
-               n = MIN(size, (brdp->pagesize - (((unsigned long) fp->f_pos) % brdp->pagesize)));
-               if (copy_from_user(memptr, chbuf, n)) {
-                       count = -EFAULT;
+               n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+               n = MIN(n, PAGE_SIZE);
+               if (copy_from_user(p, chbuf, n)) {
+                       if (count == 0)
+                               count = -EFAULT;
                        goto out;
                }
-               fp->f_pos += n;
+               spin_lock_irqsave(&brd_lock, flags);
+               EBRDENABLE(brdp);
+               memptr = (void *) EBRDGETMEMPTR(brdp, off);
+               memcpy_toio(memptr, p, n);
+               EBRDDISABLE(brdp);
+               spin_unlock_irqrestore(&brd_lock, flags);
+               off += n;
                chbuf += n;
                size -= n;
        }
 out:
-       EBRDDISABLE(brdp);
-       restore_flags(flags);
-
-       return(count);
+       free_page((unsigned long) p);
+       *offp = off;
+       return count;
 }
 
 /*****************************************************************************/
@@ -4822,16 +4341,16 @@ out:
 
 static int stli_getbrdstats(combrd_t __user *bp)
 {
-       stlibrd_t       *brdp;
-       int             i;
+       stlibrd_t *brdp;
+       int i;
 
        if (copy_from_user(&stli_brdstats, bp, sizeof(combrd_t)))
                return -EFAULT;
        if (stli_brdstats.brd >= STL_MAXBRDS)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stli_brds[stli_brdstats.brd];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
 
        memset(&stli_brdstats, 0, sizeof(combrd_t));
        stli_brdstats.brd = brdp->brdnr;
@@ -4850,7 +4369,7 @@ static int stli_getbrdstats(combrd_t __user *bp)
 
        if (copy_to_user(bp, &stli_brdstats, sizeof(combrd_t)))
                return -EFAULT;
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4861,19 +4380,19 @@ static int stli_getbrdstats(combrd_t __user *bp)
 
 static stliport_t *stli_getport(int brdnr, int panelnr, int portnr)
 {
-       stlibrd_t       *brdp;
-       int             i;
+       stlibrd_t *brdp;
+       int i;
 
-       if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
-               return((stliport_t *) NULL);
+       if (brdnr < 0 || brdnr >= STL_MAXBRDS)
+               return NULL;
        brdp = stli_brds[brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return((stliport_t *) NULL);
+       if (brdp == NULL)
+               return NULL;
        for (i = 0; (i < panelnr); i++)
                portnr += brdp->panels[i];
        if ((portnr < 0) || (portnr >= brdp->nrports))
-               return((stliport_t *) NULL);
-       return(brdp->ports[portnr]);
+               return NULL;
+       return brdp->ports[portnr];
 }
 
 /*****************************************************************************/
@@ -4892,16 +4411,16 @@ static int stli_portcmdstats(stliport_t *portp)
 
        memset(&stli_comstats, 0, sizeof(comstats_t));
 
-       if (portp == (stliport_t *) NULL)
-               return(-ENODEV);
+       if (portp == NULL)
+               return -ENODEV;
        brdp = stli_brds[portp->brdnr];
-       if (brdp == (stlibrd_t *) NULL)
-               return(-ENODEV);
+       if (brdp == NULL)
+               return -ENODEV;
 
        if (brdp->state & BST_STARTED) {
                if ((rc = stli_cmdwait(brdp, portp, A_GETSTATS,
                    &stli_cdkstats, sizeof(asystats_t), 1)) < 0)
-                       return(rc);
+                       return rc;
        } else {
                memset(&stli_cdkstats, 0, sizeof(asystats_t));
        }
@@ -4912,13 +4431,12 @@ static int stli_portcmdstats(stliport_t *portp)
        stli_comstats.state = portp->state;
        stli_comstats.flags = portp->flags;
 
-       save_flags(flags);
-       cli();
-       if (portp->tty != (struct tty_struct *) NULL) {
+       spin_lock_irqsave(&brd_lock, flags);
+       if (portp->tty != NULL) {
                if (portp->tty->driver_data == portp) {
                        stli_comstats.ttystate = portp->tty->flags;
-                       stli_comstats.rxbuffered = -1 /*portp->tty->flip.count*/;
-                       if (portp->tty->termios != (struct termios *) NULL) {
+                       stli_comstats.rxbuffered = -1;
+                       if (portp->tty->termios != NULL) {
                                stli_comstats.cflags = portp->tty->termios->c_cflag;
                                stli_comstats.iflags = portp->tty->termios->c_iflag;
                                stli_comstats.oflags = portp->tty->termios->c_oflag;
@@ -4926,7 +4444,7 @@ static int stli_portcmdstats(stliport_t *portp)
                        }
                }
        }
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        stli_comstats.txtotal = stli_cdkstats.txchars;
        stli_comstats.rxtotal = stli_cdkstats.rxchars + stli_cdkstats.ringover;
@@ -4948,7 +4466,7 @@ static int stli_portcmdstats(stliport_t *portp)
        stli_comstats.hwid = stli_cdkstats.hwid;
        stli_comstats.signals = stli_mktiocm(stli_cdkstats.signals);
 
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
@@ -4961,8 +4479,8 @@ static int stli_portcmdstats(stliport_t *portp)
 
 static int stli_getportstats(stliport_t *portp, comstats_t __user *cp)
 {
-       stlibrd_t       *brdp;
-       int             rc;
+       stlibrd_t *brdp;
+       int rc;
 
        if (!portp) {
                if (copy_from_user(&stli_comstats, cp, sizeof(comstats_t)))
@@ -4992,8 +4510,8 @@ static int stli_getportstats(stliport_t *portp, comstats_t __user *cp)
 
 static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp)
 {
-       stlibrd_t       *brdp;
-       int             rc;
+       stlibrd_t *brdp;
+       int rc;
 
        if (!portp) {
                if (copy_from_user(&stli_comstats, cp, sizeof(comstats_t)))
@@ -5031,7 +4549,7 @@ static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp)
 
 static int stli_getportstruct(stliport_t __user *arg)
 {
-       stliport_t      *portp;
+       stliport_t *portp;
 
        if (copy_from_user(&stli_dummyport, arg, sizeof(stliport_t)))
                return -EFAULT;
@@ -5052,7 +4570,7 @@ static int stli_getportstruct(stliport_t __user *arg)
 
 static int stli_getbrdstruct(stlibrd_t __user *arg)
 {
-       stlibrd_t       *brdp;
+       stlibrd_t *brdp;
 
        if (copy_from_user(&stli_dummybrd, arg, sizeof(stlibrd_t)))
                return -EFAULT;
@@ -5076,15 +4594,10 @@ static int stli_getbrdstruct(stlibrd_t __user *arg)
 
 static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
 {
-       stlibrd_t       *brdp;
-       int             brdnr, rc, done;
+       stlibrd_t *brdp;
+       int brdnr, rc, done;
        void __user *argp = (void __user *)arg;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "stli_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n",
-                       (int) ip, (int) fp, cmd, (int) arg);
-#endif
-
 /*
  *     First up handle the board independent ioctls.
  */
@@ -5115,7 +4628,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
        }
 
        if (done)
-               return(rc);
+               return rc;
 
 /*
  *     Now handle the board specific ioctls. These all depend on the
@@ -5123,12 +4636,12 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
  */
        brdnr = iminor(ip);
        if (brdnr >= STL_MAXBRDS)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stli_brds[brdnr];
        if (!brdp)
-               return(-ENODEV);
+               return -ENODEV;
        if (brdp->state == 0)
-               return(-ENODEV);
+               return -ENODEV;
 
        switch (cmd) {
        case STL_BINTR:
@@ -5152,8 +4665,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
                rc = -ENOIOCTLCMD;
                break;
        }
-
-       return(rc);
+       return rc;
 }
 
 static struct tty_operations stli_ops = {
@@ -5187,6 +4699,9 @@ int __init stli_init(void)
        int i;
        printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
 
+       spin_lock_init(&stli_lock);
+       spin_lock_init(&brd_lock);
+
        stli_initbrds();
 
        stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
@@ -5196,10 +4711,6 @@ int __init stli_init(void)
 /*
  *     Allocate a temporary write buffer.
  */
-       stli_tmpwritebuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
-       if (!stli_tmpwritebuf)
-               printk(KERN_ERR "STALLION: failed to allocate memory "
-                               "(size=%d)\n", STLI_TXBUFSIZE);
        stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
        if (!stli_txcookbuf)
                printk(KERN_ERR "STALLION: failed to allocate memory "
@@ -5213,16 +4724,11 @@ int __init stli_init(void)
                printk(KERN_ERR "STALLION: failed to register serial memory "
                                "device\n");
 
-       devfs_mk_dir("staliomem");
        istallion_class = class_create(THIS_MODULE, "staliomem");
-       for (i = 0; i < 4; i++) {
-               devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i),
-                              S_IFCHR | S_IRUSR | S_IWUSR,
-                              "staliomem/%d", i);
+       for (i = 0; i < 4; i++)
                class_device_create(istallion_class, NULL,
                                MKDEV(STL_SIOMEMMAJOR, i),
                                NULL, "staliomem%d", i);
-       }
 
 /*
  *     Set up the tty driver structure and register us as a driver.
@@ -5243,7 +4749,7 @@ int __init stli_init(void)
                printk(KERN_ERR "STALLION: failed to register serial driver\n");
                return -EBUSY;
        }
-       return(0);
+       return 0;
 }
 
 /*****************************************************************************/
index e572605252935c8562b64dbfcb6ed483fbd10756..b11a390581bad05ea210165731cb2dcbbc013944 100644 (file)
 #include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/slab.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
@@ -807,8 +806,6 @@ static int lp_register(int nr, struct parport *port)
 
        class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), NULL,
                                "lp%d", nr);
-       devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO,
-                       "printers/%d", nr);
 
        printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, 
               (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
@@ -907,7 +904,6 @@ static int __init lp_init (void)
                return -EIO;
        }
 
-       devfs_mk_dir("printers");
        lp_class = class_create(THIS_MODULE, "printer");
        if (IS_ERR(lp_class)) {
                err = PTR_ERR(lp_class);
@@ -933,7 +929,6 @@ static int __init lp_init (void)
 out_class:
        class_destroy(lp_class);
 out_devfs:
-       devfs_remove("printers");
        unregister_chrdev(LP_MAJOR, "lp");
        return err;
 }
@@ -981,10 +976,8 @@ static void lp_cleanup_module (void)
                if (lp_table[offset].dev == NULL)
                        continue;
                parport_unregister_device(lp_table[offset].dev);
-               devfs_remove("printers/%d", offset);
                class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
        }
-       devfs_remove("printers");
        class_destroy(lp_class);
 }
 
index 1fa9fa157c125652fea7cd314534992c4875a73b..6fe7b6c6c462efb0936e16f27e73a19e0438912e 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/tty.h>
 #include <linux/capability.h>
 #include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/ptrace.h>
 #include <linux/device.h>
 #include <linux/highmem.h>
@@ -941,13 +940,10 @@ static int __init chr_dev_init(void)
                printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 
        mem_class = class_create(THIS_MODULE, "mem");
-       for (i = 0; i < ARRAY_SIZE(devlist); i++) {
+       for (i = 0; i < ARRAY_SIZE(devlist); i++)
                class_device_create(mem_class, NULL,
                                        MKDEV(MEM_MAJOR, devlist[i].minor),
                                        NULL, devlist[i].name);
-               devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor),
-                               S_IFCHR | devlist[i].mode, devlist[i].name);
-       }
        
        return 0;
 }
index 96eb2a709e21d66ca7772d75c83ca79d595c81bf..dfe1cede391602b96d155a2fdb59dd0b2eebae3f 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/stat.h>
 #include <linux/init.h>
 #include <linux/device.h>
@@ -204,7 +203,7 @@ int misc_register(struct miscdevice * misc)
 {
        struct miscdevice *c;
        dev_t dev;
-       int err;
+       int err = 0;
 
        down(&misc_sem);
        list_for_each_entry(c, &misc_list, list) {
@@ -228,10 +227,6 @@ int misc_register(struct miscdevice * misc)
 
        if (misc->minor < DYNAMIC_MINORS)
                misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
-       if (misc->devfs_name[0] == '\0') {
-               snprintf(misc->devfs_name, sizeof(misc->devfs_name),
-                               "misc/%s", misc->name);
-       }
        dev = MKDEV(MISC_MAJOR, misc->minor);
 
        misc->class = class_device_create(misc_class, NULL, dev, misc->dev,
@@ -241,13 +236,6 @@ int misc_register(struct miscdevice * misc)
                goto out;
        }
 
-       err = devfs_mk_cdev(dev, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, 
-                           misc->devfs_name);
-       if (err) {
-               class_device_destroy(misc_class, dev);
-               goto out;
-       }
-
        /*
         * Add it to the front, so that later devices can "override"
         * earlier defaults
@@ -278,7 +266,6 @@ int misc_deregister(struct miscdevice * misc)
        down(&misc_sem);
        list_del(&misc->list);
        class_device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
-       devfs_remove(misc->devfs_name);
        if (i < DYNAMIC_MINORS && i>0) {
                misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
        }
index d65b3109318a347f402f51db1d9bcf6c9107bf4f..95e8122b8068d47bd617fdc7726b78eafffbdb7c 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/mmtimer.h>
 #include <linux/miscdevice.h>
 #include <linux/posix-timers.h>
@@ -694,7 +693,6 @@ static int __init mmtimer_init(void)
                return -1;
        }
 
-       strcpy(mmtimer_miscdev.devfs_name, MMTIMER_NAME);
        if (misc_register(&mmtimer_miscdev)) {
                printk(KERN_ERR "%s: failed to register device\n",
                       MMTIMER_NAME);
index f43c2e04eadd3878d57126b154afa2b4cbdc74aa..52ef61f54ba0bc225c94f10a0e2470baf9e5926e 100644 (file)
@@ -301,7 +301,7 @@ static struct tty_operations moxa_ops = {
        .tiocmset = moxa_tiocmset,
 };
 
-static spinlock_t moxa_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(moxa_lock);
 
 #ifdef CONFIG_PCI
 static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board)
@@ -342,7 +342,6 @@ static int __init moxa_init(void)
        init_MUTEX(&moxaBuffSem);
        moxaDriver->owner = THIS_MODULE;
        moxaDriver->name = "ttyMX";
-       moxaDriver->devfs_name = "tts/a";
        moxaDriver->major = ttymajor;
        moxaDriver->minor_start = 0;
        moxaDriver->type = TTY_DRIVER_TYPE_SERIAL;
index 645d9d713aec84452615d641cfb73603d4eef2b5..72cfd09091e0a63ce1587cabec737aeaeb41e127 100644 (file)
@@ -996,7 +996,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
 
        info->session = current->signal->session;
        info->pgrp = process_group(current);
-       clear_bit(TTY_DONT_FLIP, &tty->flags);
 
        /*
        status = mxser_get_msr(info->base, 0, info->port);
index b9371d5bf7906b48d4b340c5a8756c3fa132f516..603b9ade5eb089f16f041fc15e4876417a6c1505 100644 (file)
@@ -1132,7 +1132,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
  *     buffer, and once to drain the space from the (physical) beginning of
  *     the buffer to head pointer.
  *
- *     Called under the tty->atomic_read_lock sem and with TTY_DONT_FLIP set
+ *     Called under the tty->atomic_read_lock sem
  *
  */
  
@@ -1271,7 +1271,6 @@ do_it_again:
        }
 
        add_wait_queue(&tty->read_wait, &wait);
-       set_bit(TTY_DONT_FLIP, &tty->flags);
        while (nr) {
                /* First test for status change. */
                if (tty->packet && tty->link->ctrl_status) {
@@ -1315,9 +1314,7 @@ do_it_again:
                                break;
                        }
                        n_tty_set_room(tty);
-                       clear_bit(TTY_DONT_FLIP, &tty->flags);
                        timeout = schedule_timeout(timeout);
-                       set_bit(TTY_DONT_FLIP, &tty->flags);
                        continue;
                }
                __set_current_state(TASK_RUNNING);
@@ -1394,7 +1391,6 @@ do_it_again:
                if (time)
                        timeout = time;
        }
-       clear_bit(TTY_DONT_FLIP, &tty->flags);
        mutex_unlock(&tty->atomic_read_lock);
        remove_wait_queue(&tty->read_wait, &wait);
 
diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c
new file mode 100644 (file)
index 0000000..5b91e4e
--- /dev/null
@@ -0,0 +1,142 @@
+/* linux/drivers/char/nsc_gpio.c
+
+   National Semiconductor common GPIO device-file/VFS methods.
+   Allows a user space process to control the GPIO pins.
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+   Copyright (c) 2005      Jim Cromie <jim.cromie@gmail.com>
+*/
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/nsc_gpio.h>
+#include <linux/platform_device.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define NAME "nsc_gpio"
+
+void nsc_gpio_dump(struct nsc_gpio_ops *amp, unsigned index)
+{
+       /* retrieve current config w/o changing it */
+       u32 config = amp->gpio_config(index, ~0, 0);
+
+       /* user requested via 'v' command, so its INFO */
+       dev_info(amp->dev, "io%02u: 0x%04x %s %s %s %s %s %s %s\tio:%d/%d\n",
+                index, config,
+                (config & 1) ? "OE" : "TS",      /* output-enabled/tristate */
+                (config & 2) ? "PP" : "OD",      /* push pull / open drain */
+                (config & 4) ? "PUE" : "PUD",    /* pull up enabled/disabled */
+                (config & 8) ? "LOCKED" : "",    /* locked / unlocked */
+                (config & 16) ? "LEVEL" : "EDGE",/* level/edge input */
+                (config & 32) ? "HI" : "LO",     /* trigger on rise/fall edge */
+                (config & 64) ? "DEBOUNCE" : "", /* debounce */
+
+                amp->gpio_get(index), amp->gpio_current(index));
+}
+
+ssize_t nsc_gpio_write(struct file *file, const char __user *data,
+                      size_t len, loff_t *ppos)
+{
+       unsigned m = iminor(file->f_dentry->d_inode);
+       struct nsc_gpio_ops *amp = file->private_data;
+       struct device *dev = amp->dev;
+       size_t i;
+       int err = 0;
+
+       for (i = 0; i < len; ++i) {
+               char c;
+               if (get_user(c, data + i))
+                       return -EFAULT;
+               switch (c) {
+               case '0':
+                       amp->gpio_set(m, 0);
+                       break;
+               case '1':
+                       amp->gpio_set(m, 1);
+                       break;
+               case 'O':
+                       dev_dbg(dev, "GPIO%d output enabled\n", m);
+                       amp->gpio_config(m, ~1, 1);
+                       break;
+               case 'o':
+                       dev_dbg(dev, "GPIO%d output disabled\n", m);
+                       amp->gpio_config(m, ~1, 0);
+                       break;
+               case 'T':
+                       dev_dbg(dev, "GPIO%d output is push pull\n",
+                              m);
+                       amp->gpio_config(m, ~2, 2);
+                       break;
+               case 't':
+                       dev_dbg(dev, "GPIO%d output is open drain\n",
+                              m);
+                       amp->gpio_config(m, ~2, 0);
+                       break;
+               case 'P':
+                       dev_dbg(dev, "GPIO%d pull up enabled\n", m);
+                       amp->gpio_config(m, ~4, 4);
+                       break;
+               case 'p':
+                       dev_dbg(dev, "GPIO%d pull up disabled\n", m);
+                       amp->gpio_config(m, ~4, 0);
+                       break;
+               case 'v':
+                       /* View Current pin settings */
+                       amp->gpio_dump(amp, m);
+                       break;
+               case '\n':
+                       /* end of settings string, do nothing */
+                       break;
+               default:
+                       dev_err(dev, "io%2d bad setting: chr<0x%2x>\n",
+                               m, (int)c);
+                       err++;
+               }
+       }
+       if (err)
+               return -EINVAL; /* full string handled, report error */
+
+       return len;
+}
+
+ssize_t nsc_gpio_read(struct file *file, char __user * buf,
+                     size_t len, loff_t * ppos)
+{
+       unsigned m = iminor(file->f_dentry->d_inode);
+       int value;
+       struct nsc_gpio_ops *amp = file->private_data;
+
+       value = amp->gpio_get(m);
+       if (put_user(value ? '1' : '0', buf))
+               return -EFAULT;
+
+       return 1;
+}
+
+/* common file-ops routines for both scx200_gpio and pc87360_gpio */
+EXPORT_SYMBOL(nsc_gpio_write);
+EXPORT_SYMBOL(nsc_gpio_read);
+EXPORT_SYMBOL(nsc_gpio_dump);
+
+static int __init nsc_gpio_init(void)
+{
+       printk(KERN_DEBUG NAME " initializing\n");
+       return 0;
+}
+
+static void __exit nsc_gpio_cleanup(void)
+{
+       printk(KERN_DEBUG NAME " cleanup\n");
+}
+
+module_init(nsc_gpio_init);
+module_exit(nsc_gpio_cleanup);
+
+MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
+MODULE_DESCRIPTION("NatSemi GPIO Common Methods");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c
new file mode 100644 (file)
index 0000000..1c706cc
--- /dev/null
@@ -0,0 +1,340 @@
+/* linux/drivers/char/pc8736x_gpio.c
+
+   National Semiconductor PC8736x GPIO driver.  Allows a user space
+   process to play with the GPIO pins.
+
+   Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com>
+
+   adapted from linux/drivers/char/scx200_gpio.c
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>,
+*/
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/mutex.h>
+#include <linux/nsc_gpio.h>
+#include <linux/platform_device.h>
+#include <asm/uaccess.h>
+
+#define DEVNAME "pc8736x_gpio"
+
+MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
+MODULE_DESCRIPTION("NatSemi PC-8736x GPIO Pin Driver");
+MODULE_LICENSE("GPL");
+
+static int major;              /* default to dynamic major */
+module_param(major, int, 0);
+MODULE_PARM_DESC(major, "Major device number");
+
+static DEFINE_MUTEX(pc8736x_gpio_config_lock);
+static unsigned pc8736x_gpio_base;
+static u8 pc8736x_gpio_shadow[4];
+
+#define SIO_BASE1       0x2E   /* 1st command-reg to check */
+#define SIO_BASE2       0x4E   /* alt command-reg to check */
+#define SIO_BASE_OFFSET 0x20
+
+#define SIO_SID                0x20    /* SuperI/O ID Register */
+#define SIO_SID_VALUE  0xe9    /* Expected value in SuperI/O ID Register */
+
+#define SIO_CF1                0x21    /* chip config, bit0 is chip enable */
+
+#define PC8736X_GPIO_SIZE      16
+
+#define SIO_UNIT_SEL   0x7     /* unit select reg */
+#define SIO_UNIT_ACT   0x30    /* unit enable */
+#define SIO_GPIO_UNIT  0x7     /* unit number of GPIO */
+#define SIO_VLM_UNIT   0x0D
+#define SIO_TMS_UNIT   0x0E
+
+/* config-space addrs to read/write each unit's runtime addr */
+#define SIO_BASE_HADDR         0x60
+#define SIO_BASE_LADDR         0x61
+
+/* GPIO config-space pin-control addresses */
+#define SIO_GPIO_PIN_SELECT    0xF0
+#define SIO_GPIO_PIN_CONFIG     0xF1
+#define SIO_GPIO_PIN_EVENT      0xF2
+
+static unsigned char superio_cmd = 0;
+static unsigned char selected_device = 0xFF;   /* bogus start val */
+
+/* GPIO port runtime access, functionality */
+static int port_offset[] = { 0, 4, 8, 10 };    /* non-uniform offsets ! */
+/* static int event_capable[] = { 1, 1, 0, 0 };   ports 2,3 are hobbled */
+
+#define PORT_OUT       0
+#define PORT_IN                1
+#define PORT_EVT_EN    2
+#define PORT_EVT_STST  3
+
+static struct platform_device *pdev;  /* use in dev_*() */
+
+static inline void superio_outb(int addr, int val)
+{
+       outb_p(addr, superio_cmd);
+       outb_p(val, superio_cmd + 1);
+}
+
+static inline int superio_inb(int addr)
+{
+       outb_p(addr, superio_cmd);
+       return inb_p(superio_cmd + 1);
+}
+
+static int pc8736x_superio_present(void)
+{
+       /* try the 2 possible values, read a hardware reg to verify */
+       superio_cmd = SIO_BASE1;
+       if (superio_inb(SIO_SID) == SIO_SID_VALUE)
+               return superio_cmd;
+
+       superio_cmd = SIO_BASE2;
+       if (superio_inb(SIO_SID) == SIO_SID_VALUE)
+               return superio_cmd;
+
+       return 0;
+}
+
+static void device_select(unsigned devldn)
+{
+       superio_outb(SIO_UNIT_SEL, devldn);
+       selected_device = devldn;
+}
+
+static void select_pin(unsigned iminor)
+{
+       /* select GPIO port/pin from device minor number */
+       device_select(SIO_GPIO_UNIT);
+       superio_outb(SIO_GPIO_PIN_SELECT,
+                    ((iminor << 1) & 0xF0) | (iminor & 0x7));
+}
+
+static inline u32 pc8736x_gpio_configure_fn(unsigned index, u32 mask, u32 bits,
+                                           u32 func_slct)
+{
+       u32 config, new_config;
+
+       mutex_lock(&pc8736x_gpio_config_lock);
+
+       device_select(SIO_GPIO_UNIT);
+       select_pin(index);
+
+       /* read current config value */
+       config = superio_inb(func_slct);
+
+       /* set new config */
+       new_config = (config & mask) | bits;
+       superio_outb(func_slct, new_config);
+
+       mutex_unlock(&pc8736x_gpio_config_lock);
+
+       return config;
+}
+
+static u32 pc8736x_gpio_configure(unsigned index, u32 mask, u32 bits)
+{
+       return pc8736x_gpio_configure_fn(index, mask, bits,
+                                        SIO_GPIO_PIN_CONFIG);
+}
+
+static int pc8736x_gpio_get(unsigned minor)
+{
+       int port, bit, val;
+
+       port = minor >> 3;
+       bit = minor & 7;
+       val = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_IN);
+       val >>= bit;
+       val &= 1;
+
+       dev_dbg(&pdev->dev, "_gpio_get(%d from %x bit %d) == val %d\n",
+               minor, pc8736x_gpio_base + port_offset[port] + PORT_IN, bit,
+               val);
+
+       return val;
+}
+
+static void pc8736x_gpio_set(unsigned minor, int val)
+{
+       int port, bit, curval;
+
+       minor &= 0x1f;
+       port = minor >> 3;
+       bit = minor & 7;
+       curval = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_OUT);
+
+       dev_dbg(&pdev->dev, "addr:%x cur:%x bit-pos:%d cur-bit:%x + new:%d -> bit-new:%d\n",
+               pc8736x_gpio_base + port_offset[port] + PORT_OUT,
+               curval, bit, (curval & ~(1 << bit)), val, (val << bit));
+
+       val = (curval & ~(1 << bit)) | (val << bit);
+
+       dev_dbg(&pdev->dev, "gpio_set(minor:%d port:%d bit:%d)"
+               " %2x -> %2x\n", minor, port, bit, curval, val);
+
+       outb_p(val, pc8736x_gpio_base + port_offset[port] + PORT_OUT);
+
+       curval = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_OUT);
+       val = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_IN);
+
+       dev_dbg(&pdev->dev, "wrote %x, read: %x\n", curval, val);
+       pc8736x_gpio_shadow[port] = val;
+}
+
+static void pc8736x_gpio_set_high(unsigned index)
+{
+       pc8736x_gpio_set(index, 1);
+}
+
+static void pc8736x_gpio_set_low(unsigned index)
+{
+       pc8736x_gpio_set(index, 0);
+}
+
+static int pc8736x_gpio_current(unsigned minor)
+{
+       int port, bit;
+       minor &= 0x1f;
+       port = minor >> 3;
+       bit = minor & 7;
+       return ((pc8736x_gpio_shadow[port] >> bit) & 0x01);
+}
+
+static void pc8736x_gpio_change(unsigned index)
+{
+       pc8736x_gpio_set(index, !pc8736x_gpio_current(index));
+}
+
+static struct nsc_gpio_ops pc8736x_access = {
+       .owner          = THIS_MODULE,
+       .gpio_config    = pc8736x_gpio_configure,
+       .gpio_dump      = nsc_gpio_dump,
+       .gpio_get       = pc8736x_gpio_get,
+       .gpio_set       = pc8736x_gpio_set,
+       .gpio_set_high  = pc8736x_gpio_set_high,
+       .gpio_set_low   = pc8736x_gpio_set_low,
+       .gpio_change    = pc8736x_gpio_change,
+       .gpio_current   = pc8736x_gpio_current
+};
+
+static int pc8736x_gpio_open(struct inode *inode, struct file *file)
+{
+       unsigned m = iminor(inode);
+       file->private_data = &pc8736x_access;
+
+       dev_dbg(&pdev->dev, "open %d\n", m);
+
+       if (m > 63)
+               return -EINVAL;
+       return nonseekable_open(inode, file);
+}
+
+static struct file_operations pc8736x_gpio_fops = {
+       .owner  = THIS_MODULE,
+       .open   = pc8736x_gpio_open,
+       .write  = nsc_gpio_write,
+       .read   = nsc_gpio_read,
+};
+
+static void __init pc8736x_init_shadow(void)
+{
+       int port;
+
+       /* read the current values driven on the GPIO signals */
+       for (port = 0; port < 4; ++port)
+               pc8736x_gpio_shadow[port]
+                   = inb_p(pc8736x_gpio_base + port_offset[port]
+                           + PORT_OUT);
+
+}
+
+static int __init pc8736x_gpio_init(void)
+{
+       int rc = 0;
+
+       pdev = platform_device_alloc(DEVNAME, 0);
+       if (!pdev)
+               return -ENOMEM;
+
+       rc = platform_device_add(pdev);
+       if (rc) {
+               rc = -ENODEV;
+               goto undo_platform_dev_alloc;
+       }
+       dev_info(&pdev->dev, "NatSemi pc8736x GPIO Driver Initializing\n");
+
+       if (!pc8736x_superio_present()) {
+               rc = -ENODEV;
+               dev_err(&pdev->dev, "no device found\n");
+               goto undo_platform_dev_add;
+       }
+       pc8736x_access.dev = &pdev->dev;
+
+       /* Verify that chip and it's GPIO unit are both enabled.
+          My BIOS does this, so I take minimum action here
+        */
+       rc = superio_inb(SIO_CF1);
+       if (!(rc & 0x01)) {
+               rc = -ENODEV;
+               dev_err(&pdev->dev, "device not enabled\n");
+               goto undo_platform_dev_add;
+       }
+       device_select(SIO_GPIO_UNIT);
+       if (!superio_inb(SIO_UNIT_ACT)) {
+               rc = -ENODEV;
+               dev_err(&pdev->dev, "GPIO unit not enabled\n");
+               goto undo_platform_dev_add;
+       }
+
+       /* read the GPIO unit base addr that chip responds to */
+       pc8736x_gpio_base = (superio_inb(SIO_BASE_HADDR) << 8
+                            | superio_inb(SIO_BASE_LADDR));
+
+       if (!request_region(pc8736x_gpio_base, 16, DEVNAME)) {
+               rc = -ENODEV;
+               dev_err(&pdev->dev, "GPIO ioport %x busy\n",
+                       pc8736x_gpio_base);
+               goto undo_platform_dev_add;
+       }
+       dev_info(&pdev->dev, "GPIO ioport %x reserved\n", pc8736x_gpio_base);
+
+       rc = register_chrdev(major, DEVNAME, &pc8736x_gpio_fops);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "register-chrdev failed: %d\n", rc);
+               goto undo_platform_dev_add;
+       }
+       if (!major) {
+               major = rc;
+               dev_dbg(&pdev->dev, "got dynamic major %d\n", major);
+       }
+
+       pc8736x_init_shadow();
+       return 0;
+
+undo_platform_dev_add:
+       platform_device_put(pdev);
+undo_platform_dev_alloc:
+       kfree(pdev);
+       return rc;
+}
+
+static void __exit pc8736x_gpio_cleanup(void)
+{
+       dev_dbg(&pdev->dev, " cleanup\n");
+
+       release_region(pc8736x_gpio_base, 16);
+
+       unregister_chrdev(major, DEVNAME);
+}
+
+EXPORT_SYMBOL(pc8736x_access);
+
+module_init(pc8736x_gpio_init);
+module_exit(pc8736x_gpio_cleanup);
index bee6c47b45bdd162e33e50e32171667dd6df8df8..24231d9743dc297a7db77bbb0796e190163591ca 100644 (file)
@@ -60,7 +60,6 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/device.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/ioctl.h>
 #include <linux/parport.h>
 #include <linux/ctype.h>
@@ -770,7 +769,7 @@ static struct parport_driver pp_driver = {
 
 static int __init ppdev_init (void)
 {
-       int i, err = 0;
+       int err = 0;
 
        if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
                printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
@@ -782,11 +781,6 @@ static int __init ppdev_init (void)
                err = PTR_ERR(ppdev_class);
                goto out_chrdev;
        }
-       devfs_mk_dir("parports");
-       for (i = 0; i < PARPORT_MAX; i++) {
-               devfs_mk_cdev(MKDEV(PP_MAJOR, i),
-                               S_IFCHR | S_IRUGO | S_IWUGO, "parports/%d", i);
-       }
        if (parport_register_driver(&pp_driver)) {
                printk (KERN_WARNING CHRDEV ": unable to register with parport\n");
                goto out_class;
@@ -796,9 +790,6 @@ static int __init ppdev_init (void)
        goto out;
 
 out_class:
-       for (i = 0; i < PARPORT_MAX; i++)
-               devfs_remove("parports/%d", i);
-       devfs_remove("parports");
        class_destroy(ppdev_class);
 out_chrdev:
        unregister_chrdev(PP_MAJOR, CHRDEV);
@@ -808,12 +799,8 @@ out:
 
 static void __exit ppdev_cleanup (void)
 {
-       int i;
        /* Clean up all parport stuff */
-       for (i = 0; i < PARPORT_MAX; i++)
-               devfs_remove("parports/%d", i);
        parport_unregister_driver(&pp_driver);
-       devfs_remove("parports");
        class_destroy(ppdev_class);
        unregister_chrdev (PP_MAJOR, CHRDEV);
 }
index 9b5a2c0e7008c82183649e6006784088ceabd220..9491e43075667be1f1e48ada2803bc77ae5a7b54 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/sysctl.h>
 
 #include <asm/uaccess.h>
@@ -101,7 +100,7 @@ static void pty_unthrottle(struct tty_struct * tty)
  *
  * FIXME: Our pty_write method is called with our ldisc lock held but
  * not our partners. We can't just take the other one blindly without
- * risking deadlocks.  There is also the small matter of TTY_DONT_FLIP
+ * risking deadlocks.
  */
 static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
 {
@@ -265,7 +264,6 @@ static void __init legacy_pty_init(void)
        pty_driver->owner = THIS_MODULE;
        pty_driver->driver_name = "pty_master";
        pty_driver->name = "pty";
-       pty_driver->devfs_name = "pty/m";
        pty_driver->major = PTY_MASTER_MAJOR;
        pty_driver->minor_start = 0;
        pty_driver->type = TTY_DRIVER_TYPE_PTY;
@@ -283,7 +281,6 @@ static void __init legacy_pty_init(void)
        pty_slave_driver->owner = THIS_MODULE;
        pty_slave_driver->driver_name = "pty_slave";
        pty_slave_driver->name = "ttyp";
-       pty_slave_driver->devfs_name = "pty/s";
        pty_slave_driver->major = PTY_SLAVE_MAJOR;
        pty_slave_driver->minor_start = 0;
        pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;
@@ -351,7 +348,6 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
 
 static void __init unix98_pty_init(void)
 {
-       devfs_mk_dir("pts");
        ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
        if (!ptm_driver)
                panic("Couldn't allocate Unix98 ptm driver");
@@ -372,7 +368,7 @@ static void __init unix98_pty_init(void)
        ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
        ptm_driver->init_termios.c_lflag = 0;
        ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-               TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM;
+               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
        ptm_driver->other = pts_driver;
        tty_set_operations(ptm_driver, &pty_ops);
        ptm_driver->ioctl = pty_unix98_ioctl;
@@ -387,7 +383,7 @@ static void __init unix98_pty_init(void)
        pts_driver->init_termios = tty_std_termios;
        pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
        pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-               TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM;
+               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
        pts_driver->other = ptm_driver;
        tty_set_operations(pts_driver, &pty_ops);
        
index 15a7b408652449ee421a14cf1e1fcc56004eed4e..9bf97c5e38c041e47dbb340f314740ddc43f3c5e 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <linux/init.h>
 #include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/major.h>
 #include <linux/blkdev.h>
 #include <linux/module.h>
@@ -288,7 +287,6 @@ static struct cdev raw_cdev = {
 
 static int __init raw_init(void)
 {
-       int i;
        dev_t dev = MKDEV(RAW_MAJOR, 0);
 
        if (register_chrdev_region(dev, MAX_RAW_MINORS, "raw"))
@@ -310,13 +308,6 @@ static int __init raw_init(void)
        }
        class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
 
-       devfs_mk_cdev(MKDEV(RAW_MAJOR, 0),
-                     S_IFCHR | S_IRUGO | S_IWUGO,
-                     "raw/rawctl");
-       for (i = 1; i < MAX_RAW_MINORS; i++)
-               devfs_mk_cdev(MKDEV(RAW_MAJOR, i),
-                             S_IFCHR | S_IRUGO | S_IWUGO,
-                             "raw/raw%d", i);
        return 0;
 
 error:
@@ -326,12 +317,6 @@ error:
 
 static void __exit raw_exit(void)
 {
-       int i;
-
-       for (i = 1; i < MAX_RAW_MINORS; i++)
-               devfs_remove("raw/raw%d", i);
-       devfs_remove("raw/rawctl");
-       devfs_remove("raw");
        class_device_destroy(raw_class, MKDEV(RAW_MAJOR, 0));
        class_destroy(raw_class);
        cdev_del(&raw_cdev);
index 657c0d88f48c439e6788e4bf4d9bc2e24c1a5550..c84c3c3f10c3e4f27950c2e9075379fe87083679 100644 (file)
@@ -1634,7 +1634,6 @@ static inline int rc_init_drivers(void)
        memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
        riscom_driver->owner = THIS_MODULE;
        riscom_driver->name = "ttyL";
-       riscom_driver->devfs_name = "tts/L";
        riscom_driver->major = RISCOM8_NORMAL_MAJOR;
        riscom_driver->type = TTY_DRIVER_TYPE_SERIAL;
        riscom_driver->subtype = SERIAL_TYPE_NORMAL;
index 0708c5164c830b7fd6d9863a3e65efac3b9e5289..0ac131881322c96920b049c45e8aa64d5fbdb635 100644 (file)
@@ -2426,8 +2426,7 @@ static int __init rp_init(void)
         */
 
        rocket_driver->owner = THIS_MODULE;
-       rocket_driver->flags = TTY_DRIVER_NO_DEVFS;
-       rocket_driver->devfs_name = "tts/R";
+       rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
        rocket_driver->name = "ttyR";
        rocket_driver->driver_name = "Comtrol RocketPort";
        rocket_driver->major = TTY_ROCKET_MAJOR;
@@ -2438,7 +2437,7 @@ static int __init rp_init(void)
        rocket_driver->init_termios.c_cflag =
            B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 #ifdef ROCKET_SOFT_FLOW
-       rocket_driver->flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       rocket_driver->flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 #endif
        tty_set_operations(rocket_driver, &rocket_ops);
 
index 664a6e97eb1a8012475625af6383825a3d885e20..5a280a330401f76924b57d4031457439670f504e 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/drivers/char/scx200_gpio.c 
+/* linux/drivers/char/scx200_gpio.c
 
    National Semiconductor SCx200 GPIO driver.  Allows a user space
    process to play with the GPIO pins.
@@ -6,17 +6,26 @@
    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
 
 #include <linux/config.h>
+#include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
+#include <linux/types.h>
+#include <linux/cdev.h>
+
 #include <linux/scx200_gpio.h>
+#include <linux/nsc_gpio.h>
 
 #define NAME "scx200_gpio"
+#define DEVNAME NAME
+
+static struct platform_device *pdev;
 
 MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
 MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
@@ -26,70 +35,23 @@ static int major = 0;               /* default to dynamic major */
 module_param(major, int, 0);
 MODULE_PARM_DESC(major, "Major device number");
 
-static ssize_t scx200_gpio_write(struct file *file, const char __user *data, 
-                                size_t len, loff_t *ppos)
-{
-       unsigned m = iminor(file->f_dentry->d_inode);
-       size_t i;
-
-       for (i = 0; i < len; ++i) {
-               char c;
-               if (get_user(c, data+i))
-                       return -EFAULT;
-               switch (c)
-               {
-               case '0': 
-                       scx200_gpio_set(m, 0); 
-                       break;
-               case '1': 
-                       scx200_gpio_set(m, 1); 
-                       break;
-               case 'O':
-                       printk(KERN_INFO NAME ": GPIO%d output enabled\n", m);
-                       scx200_gpio_configure(m, ~1, 1);
-                       break;
-               case 'o':
-                       printk(KERN_INFO NAME ": GPIO%d output disabled\n", m);
-                       scx200_gpio_configure(m, ~1, 0);
-                       break;
-               case 'T':
-                       printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m);
-                       scx200_gpio_configure(m, ~2, 2);
-                       break;
-               case 't':
-                       printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m);
-                       scx200_gpio_configure(m, ~2, 0);
-                       break;
-               case 'P':
-                       printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m);
-                       scx200_gpio_configure(m, ~4, 4);
-                       break;
-               case 'p':
-                       printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m);
-                       scx200_gpio_configure(m, ~4, 0);
-                       break;
-               }
-       }
-
-       return len;
-}
-
-static ssize_t scx200_gpio_read(struct file *file, char __user *buf,
-                               size_t len, loff_t *ppos)
-{
-       unsigned m = iminor(file->f_dentry->d_inode);
-       int value;
-
-       value = scx200_gpio_get(m);
-       if (put_user(value ? '1' : '0', buf))
-               return -EFAULT;
-       
-       return 1;
-}
+struct nsc_gpio_ops scx200_access = {
+       .owner          = THIS_MODULE,
+       .gpio_config    = scx200_gpio_configure,
+       .gpio_dump      = nsc_gpio_dump,
+       .gpio_get       = scx200_gpio_get,
+       .gpio_set       = scx200_gpio_set,
+       .gpio_set_high  = scx200_gpio_set_high,
+       .gpio_set_low   = scx200_gpio_set_low,
+       .gpio_change    = scx200_gpio_change,
+       .gpio_current   = scx200_gpio_current
+};
 
 static int scx200_gpio_open(struct inode *inode, struct file *file)
 {
        unsigned m = iminor(inode);
+       file->private_data = &scx200_access;
+
        if (m > 63)
                return -EINVAL;
        return nonseekable_open(inode, file);
@@ -103,47 +65,81 @@ static int scx200_gpio_release(struct inode *inode, struct file *file)
 
 static struct file_operations scx200_gpio_fops = {
        .owner   = THIS_MODULE,
-       .write   = scx200_gpio_write,
-       .read    = scx200_gpio_read,
+       .write   = nsc_gpio_write,
+       .read    = nsc_gpio_read,
        .open    = scx200_gpio_open,
        .release = scx200_gpio_release,
 };
 
+struct cdev *scx200_devices;
+static int num_pins = 32;
+
 static int __init scx200_gpio_init(void)
 {
-       int r;
-
-       printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n");
+       int rc, i;
+       dev_t dev = MKDEV(major, 0);
 
        if (!scx200_gpio_present()) {
-               printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+               printk(KERN_ERR NAME ": no SCx200 gpio present\n");
                return -ENODEV;
        }
 
-       r = register_chrdev(major, NAME, &scx200_gpio_fops);
-       if (r < 0) {
-               printk(KERN_ERR NAME ": unable to register character device\n");
-               return r;
+       /* support dev_dbg() with pdev->dev */
+       pdev = platform_device_alloc(DEVNAME, 0);
+       if (!pdev)
+               return -ENOMEM;
+
+       rc = platform_device_add(pdev);
+       if (rc)
+               goto undo_malloc;
+
+       /* nsc_gpio uses dev_dbg(), so needs this */
+       scx200_access.dev = &pdev->dev;
+
+       if (major)
+               rc = register_chrdev_region(dev, num_pins, "scx200_gpio");
+       else {
+               rc = alloc_chrdev_region(&dev, 0, num_pins, "scx200_gpio");
+               major = MAJOR(dev);
        }
-       if (!major) {
-               major = r;
-               printk(KERN_DEBUG NAME ": got dynamic major %d\n", major);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc);
+               goto undo_platform_device_add;
+       }
+       scx200_devices = kzalloc(num_pins * sizeof(struct cdev), GFP_KERNEL);
+       if (!scx200_devices) {
+               rc = -ENOMEM;
+               goto undo_chrdev_region;
+       }
+       for (i = 0; i < num_pins; i++) {
+               struct cdev *cdev = &scx200_devices[i];
+               cdev_init(cdev, &scx200_gpio_fops);
+               cdev->owner = THIS_MODULE;
+               rc = cdev_add(cdev, MKDEV(major, i), 1);
+               /* tolerate 'minor' errors */
+               if (rc)
+                       dev_err(&pdev->dev, "Error %d on minor %d", rc, i);
        }
 
-       return 0;
+       return 0; /* succeed */
+
+undo_chrdev_region:
+       unregister_chrdev_region(dev, num_pins);
+undo_platform_device_add:
+       platform_device_put(pdev);
+undo_malloc:
+       kfree(pdev);
+       return rc;
 }
 
 static void __exit scx200_gpio_cleanup(void)
 {
-       unregister_chrdev(major, NAME);
+       kfree(scx200_devices);
+       unregister_chrdev_region(MKDEV(major, 0), num_pins);
+       platform_device_put(pdev);
+       platform_device_unregister(pdev);
+       /* kfree(pdev); */
 }
 
 module_init(scx200_gpio_init);
 module_exit(scx200_gpio_cleanup);
-
-/*
-    Local variables:
-        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
-        c-basic-offset: 8
-    End:
-*/
index 037c940ac71b8bb10b4dd2788aff141980ddba63..c851eeaa406913967ba03f154d1fdba1e2d6835c 100644 (file)
@@ -2235,7 +2235,6 @@ scrn[1] = '\0';
     /* Initialize the tty_driver structure */
     
     cy_serial_driver->owner = THIS_MODULE;
-    cy_serial_driver->devfs_name = "tts/";
     cy_serial_driver->name = "ttyS";
     cy_serial_driver->major = TTY_MAJOR;
     cy_serial_driver->minor_start = 64;
index 1b5330299e30fa965086eae13d601a1e80e29be3..d2d6b01dcd05a1168dbd7795ebd13d5c5be32dc9 100644 (file)
@@ -2477,7 +2477,7 @@ static int __init specialix_init(void)
 #endif
 
        for (i = 0; i < SX_NBOARD; i++)
-               sx_board[i].lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&sx_board[i].lock);
 
        if (sx_init_drivers()) {
                func_exit();
index a9c5a7230f8958b5d8ee1338fa88c40cddf79a58..0f7a542d9041052f730ecef16aaead6e1bfbdb4b 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 
@@ -140,15 +139,6 @@ static char        *stl_drvversion = "5.6.0";
 
 static struct tty_driver       *stl_serial;
 
-/*
- *     We will need to allocate a temporary write buffer for chars that
- *     come direct from user space. The problem is that a copy from user
- *     space might cause a page fault (typically on a system that is
- *     swapping!). All ports will share one buffer - since if the system
- *     is already swapping a shared buffer won't make things any worse.
- */
-static char                    *stl_tmpwritebuf;
-
 /*
  *     Define a local default termios struct. All ports will be created
  *     with this termios initially. Basically all it defines is a raw port
@@ -362,6 +352,14 @@ static unsigned char       stl_vecmap[] = {
        0xff, 0xff, 0x00, 0x02, 0x01, 0xff, 0xff, 0x03
 };
 
+/*
+ *     Lock ordering is that you may not take stallion_lock holding
+ *     brd_lock.
+ */
+
+static spinlock_t brd_lock;            /* Guard the board mapping */
+static spinlock_t stallion_lock;       /* Guard the tty driver */
+
 /*
  *     Set up enable and disable macros for the ECH boards. They require
  *     the secondary io address space to be activated and deactivated.
@@ -725,17 +723,7 @@ static struct class *stallion_class;
 
 static int __init stallion_module_init(void)
 {
-       unsigned long   flags;
-
-#ifdef DEBUG
-       printk("init_module()\n");
-#endif
-
-       save_flags(flags);
-       cli();
        stl_init();
-       restore_flags(flags);
-
        return 0;
 }
 
@@ -746,7 +734,6 @@ static void __exit stallion_module_exit(void)
        stlbrd_t        *brdp;
        stlpanel_t      *panelp;
        stlport_t       *portp;
-       unsigned long   flags;
        int             i, j, k;
 
 #ifdef DEBUG
@@ -756,9 +743,6 @@ static void __exit stallion_module_exit(void)
        printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle,
                stl_drvversion);
 
-       save_flags(flags);
-       cli();
-
 /*
  *     Free up all allocated resources used by the ports. This includes
  *     memory and interrupts. As part of this process we will also do
@@ -770,21 +754,15 @@ static void __exit stallion_module_exit(void)
        if (i) {
                printk("STALLION: failed to un-register tty driver, "
                        "errno=%d\n", -i);
-               restore_flags(flags);
                return;
        }
-       for (i = 0; i < 4; i++) {
-               devfs_remove("staliomem/%d", i);
+       for (i = 0; i < 4; i++)
                class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
-       }
-       devfs_remove("staliomem");
        if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
                printk("STALLION: failed to un-register serial memory device, "
                        "errno=%d\n", -i);
        class_destroy(stallion_class);
 
-       kfree(stl_tmpwritebuf);
-
        for (i = 0; (i < stl_nrbrds); i++) {
                if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL)
                        continue;
@@ -814,8 +792,6 @@ static void __exit stallion_module_exit(void)
                kfree(brdp);
                stl_brds[i] = (stlbrd_t *) NULL;
        }
-
-       restore_flags(flags);
 }
 
 module_init(stallion_module_init);
@@ -948,7 +924,7 @@ static stlbrd_t *stl_allocbrd(void)
 
        brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL);
        if (!brdp) {
-               printk("STALLION: failed to allocate memory (size=%d)\n",
+               printk("STALLION: failed to allocate memory (size=%Zd)\n",
                        sizeof(stlbrd_t));
                return NULL;
        }
@@ -1066,16 +1042,17 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp)
        rc = 0;
        doclocal = 0;
 
+       spin_lock_irqsave(&stallion_lock, flags);
+
        if (portp->tty->termios->c_cflag & CLOCAL)
                doclocal++;
 
-       save_flags(flags);
-       cli();
        portp->openwaitcnt++;
        if (! tty_hung_up_p(filp))
                portp->refcount--;
 
        for (;;) {
+               /* Takes brd_lock internally */
                stl_setsignals(portp, 1, 1);
                if (tty_hung_up_p(filp) ||
                    ((portp->flags & ASYNC_INITIALIZED) == 0)) {
@@ -1093,13 +1070,14 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp)
                        rc = -ERESTARTSYS;
                        break;
                }
+               /* FIXME */
                interruptible_sleep_on(&portp->open_wait);
        }
 
        if (! tty_hung_up_p(filp))
                portp->refcount++;
        portp->openwaitcnt--;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&stallion_lock, flags);
 
        return rc;
 }
@@ -1119,16 +1097,15 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
        if (portp == (stlport_t *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&stallion_lock, flags);
        if (tty_hung_up_p(filp)) {
-               restore_flags(flags);
+               spin_unlock_irqrestore(&stallion_lock, flags);
                return;
        }
        if ((tty->count == 1) && (portp->refcount != 1))
                portp->refcount = 1;
        if (portp->refcount-- > 1) {
-               restore_flags(flags);
+               spin_unlock_irqrestore(&stallion_lock, flags);
                return;
        }
 
@@ -1142,11 +1119,18 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
  *     (The sc26198 has no "end-of-data" interrupt only empty FIFO)
  */
        tty->closing = 1;
+
+       spin_unlock_irqrestore(&stallion_lock, flags);
+
        if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
                tty_wait_until_sent(tty, portp->closing_wait);
        stl_waituntilsent(tty, (HZ / 2));
 
+
+       spin_lock_irqsave(&stallion_lock, flags);
        portp->flags &= ~ASYNC_INITIALIZED;
+       spin_unlock_irqrestore(&stallion_lock, flags);
+
        stl_disableintrs(portp);
        if (tty->termios->c_cflag & HUPCL)
                stl_setsignals(portp, 0, 0);
@@ -1173,7 +1157,6 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
 
        portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
        wake_up_interruptible(&portp->close_wait);
-       restore_flags(flags);
 }
 
 /*****************************************************************************/
@@ -1195,9 +1178,6 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count
                (int) tty, (int) buf, count);
 #endif
 
-       if ((tty == (struct tty_struct *) NULL) ||
-           (stl_tmpwritebuf == (char *) NULL))
-               return 0;
        portp = tty->driver_data;
        if (portp == (stlport_t *) NULL)
                return 0;
@@ -1302,11 +1282,6 @@ static void stl_flushchars(struct tty_struct *tty)
        if (portp->tx.buf == (char *) NULL)
                return;
 
-#if 0
-       if (tty->stopped || tty->hw_stopped ||
-           (portp->tx.head == portp->tx.tail))
-               return;
-#endif
        stl_startrxtx(portp, -1, 1);
 }
 
@@ -1977,12 +1952,14 @@ static int stl_eiointr(stlbrd_t *brdp)
        unsigned int    iobase;
        int             handled = 0;
 
+       spin_lock(&brd_lock);
        panelp = brdp->panels[0];
        iobase = panelp->iobase;
        while (inb(brdp->iostatus) & EIO_INTRPEND) {
                handled = 1;
                (* panelp->isr)(panelp, iobase);
        }
+       spin_unlock(&brd_lock);
        return handled;
 }
 
@@ -2168,7 +2145,7 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
                portp = kzalloc(sizeof(stlport_t), GFP_KERNEL);
                if (!portp) {
                        printk("STALLION: failed to allocate memory "
-                               "(size=%d)\n", sizeof(stlport_t));
+                               "(size=%Zd)\n", sizeof(stlport_t));
                        break;
                }
 
@@ -2304,7 +2281,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
        panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
        if (!panelp) {
                printk(KERN_WARNING "STALLION: failed to allocate memory "
-                       "(size=%d)\n", sizeof(stlpanel_t));
+                       "(size=%Zd)\n", sizeof(stlpanel_t));
                return -ENOMEM;
        }
 
@@ -2478,7 +2455,7 @@ static inline int stl_initech(stlbrd_t *brdp)
                panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
                if (!panelp) {
                        printk("STALLION: failed to allocate memory "
-                               "(size=%d)\n", sizeof(stlpanel_t));
+                               "(size=%Zd)\n", sizeof(stlpanel_t));
                        break;
                }
                panelp->magic = STL_PANELMAGIC;
@@ -2879,8 +2856,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
        portp->stats.lflags = 0;
        portp->stats.rxbuffered = 0;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&stallion_lock, flags);
        if (portp->tty != (struct tty_struct *) NULL) {
                if (portp->tty->driver_data == portp) {
                        portp->stats.ttystate = portp->tty->flags;
@@ -2894,7 +2870,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
                        }
                }
        }
-       restore_flags(flags);
+       spin_unlock_irqrestore(&stallion_lock, flags);
 
        head = portp->tx.head;
        tail = portp->tx.tail;
@@ -3049,42 +3025,31 @@ static int __init stl_init(void)
        int i;
        printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
 
+       spin_lock_init(&stallion_lock);
+       spin_lock_init(&brd_lock);
+
        stl_initbrds();
 
        stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
        if (!stl_serial)
                return -1;
 
-/*
- *     Allocate a temporary write buffer.
- */
-       stl_tmpwritebuf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
-       if (!stl_tmpwritebuf)
-               printk("STALLION: failed to allocate memory (size=%d)\n",
-                       STL_TXBUFSIZE);
-
 /*
  *     Set up a character driver for per board stuff. This is mainly used
  *     to do stats ioctls on the ports.
  */
        if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
                printk("STALLION: failed to register serial board device\n");
-       devfs_mk_dir("staliomem");
 
        stallion_class = class_create(THIS_MODULE, "staliomem");
-       for (i = 0; i < 4; i++) {
-               devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i),
-                               S_IFCHR|S_IRUSR|S_IWUSR,
-                               "staliomem/%d", i);
+       for (i = 0; i < 4; i++)
                class_device_create(stallion_class, NULL,
                                    MKDEV(STL_SIOMEMMAJOR, i), NULL,
                                    "staliomem%d", i);
-       }
 
        stl_serial->owner = THIS_MODULE;
        stl_serial->driver_name = stl_drvname;
        stl_serial->name = "ttyE";
-       stl_serial->devfs_name = "tts/E";
        stl_serial->major = STL_SERIALMAJOR;
        stl_serial->minor_start = 0;
        stl_serial->type = TTY_DRIVER_TYPE_SERIAL;
@@ -3147,11 +3112,13 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
        unsigned int    gfrcr;
        int             chipmask, i, j;
        int             nrchips, uartaddr, ioaddr;
+       unsigned long   flags;
 
 #ifdef DEBUG
        printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);
 #endif
 
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(panelp->brdnr, panelp->pagenr);
 
 /*
@@ -3189,6 +3156,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
        }
 
        BRDDISABLE(panelp->brdnr);
+       spin_unlock_irqrestore(&brd_lock, flags);
        return chipmask;
 }
 
@@ -3200,6 +3168,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
 
 static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp)
 {
+       unsigned long flags;
 #ifdef DEBUG
        printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n",
                (int) brdp, (int) panelp, (int) portp);
@@ -3209,6 +3178,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po
            (portp == (stlport_t *) NULL))
                return;
 
+       spin_lock_irqsave(&brd_lock, flags);
        portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) ||
                (portp->portnr < 8)) ? 0 : EREG_BANKSIZE);
        portp->uartaddr = (portp->portnr & 0x04) << 5;
@@ -3219,6 +3189,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po
        stl_cd1400setreg(portp, LIVR, (portp->portnr << 3));
        portp->hwid = stl_cd1400getreg(portp, GFRCR);
        BRDDISABLE(portp->brdnr);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3428,8 +3399,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
                tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3));
        srer = stl_cd1400getreg(portp, SRER);
@@ -3466,7 +3436,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
                portp->sigs &= ~TIOCM_CD;
        stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron));
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3492,8 +3462,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts)
        if (rts > 0)
                msvr2 = MSVR2_RTS;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        if (rts >= 0)
@@ -3501,7 +3470,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts)
        if (dtr >= 0)
                stl_cd1400setreg(portp, MSVR1, msvr1);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3520,14 +3489,13 @@ static int stl_cd1400getsignals(stlport_t *portp)
        printk("stl_cd1400getsignals(portp=%x)\n", (int) portp);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        msvr1 = stl_cd1400getreg(portp, MSVR1);
        msvr2 = stl_cd1400getreg(portp, MSVR2);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        sigs = 0;
        sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0;
@@ -3569,15 +3537,14 @@ static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx)
        else if (rx > 0)
                ccr |= CCR_RXENABLE;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        stl_cd1400ccrwait(portp);
        stl_cd1400setreg(portp, CCR, ccr);
        stl_cd1400ccrwait(portp);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3609,8 +3576,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx)
        else if (rx > 0)
                sreron |= SRER_RXDATA;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        stl_cd1400setreg(portp, SRER,
@@ -3618,7 +3584,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx)
        BRDDISABLE(portp->brdnr);
        if (tx > 0)
                set_bit(ASYI_TXBUSY, &portp->istate);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3634,13 +3600,12 @@ static void stl_cd1400disableintrs(stlport_t *portp)
 #ifdef DEBUG
        printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp);
 #endif
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        stl_cd1400setreg(portp, SRER, 0);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3653,8 +3618,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len)
        printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        stl_cd1400setreg(portp, SRER,
@@ -3664,7 +3628,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len)
        portp->brklen = len;
        if (len == 1)
                portp->stats.txbreaks++;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3688,8 +3652,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state)
        if (tty == (struct tty_struct *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
 
@@ -3729,7 +3692,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state)
        }
 
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3753,8 +3716,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state)
        if (tty == (struct tty_struct *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        if (state) {
@@ -3769,7 +3731,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state)
                stl_cd1400ccrwait(portp);
        }
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3785,8 +3747,7 @@ static void stl_cd1400flush(stlport_t *portp)
        if (portp == (stlport_t *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
        stl_cd1400ccrwait(portp);
@@ -3794,7 +3755,7 @@ static void stl_cd1400flush(stlport_t *portp)
        stl_cd1400ccrwait(portp);
        portp->tx.tail = portp->tx.head;
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -3833,6 +3794,7 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
                (int) panelp, iobase);
 #endif
 
+       spin_lock(&brd_lock);
        outb(SVRR, iobase);
        svrtype = inb(iobase + EREG_DATA);
        if (panelp->nrports > 4) {
@@ -3846,6 +3808,8 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
                stl_cd1400txisr(panelp, iobase);
        else if (svrtype & SVRR_MDM)
                stl_cd1400mdmisr(panelp, iobase);
+
+       spin_unlock(&brd_lock);
 }
 
 /*****************************************************************************/
@@ -4433,8 +4397,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
                tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_sc26198setreg(portp, IMR, 0);
        stl_sc26198updatereg(portp, MR0, mr0);
@@ -4461,7 +4424,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
        portp->imr = (portp->imr & ~imroff) | imron;
        stl_sc26198setreg(portp, IMR, portp->imr);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4491,13 +4454,12 @@ static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts)
        else if (rts > 0)
                iopioron |= IPR_RTS;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_sc26198setreg(portp, IOPIOR,
                ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron));
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4516,12 +4478,11 @@ static int stl_sc26198getsignals(stlport_t *portp)
        printk("stl_sc26198getsignals(portp=%x)\n", (int) portp);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        ipr = stl_sc26198getreg(portp, IPR);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        sigs = 0;
        sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD;
@@ -4558,13 +4519,12 @@ static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx)
        else if (rx > 0)
                ccr |= CR_RXENABLE;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_sc26198setreg(portp, SCCR, ccr);
        BRDDISABLE(portp->brdnr);
        portp->crenable = ccr;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4593,15 +4553,14 @@ static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx)
        else if (rx > 0)
                imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_sc26198setreg(portp, IMR, imr);
        BRDDISABLE(portp->brdnr);
        portp->imr = imr;
        if (tx > 0)
                set_bit(ASYI_TXBUSY, &portp->istate);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4618,13 +4577,12 @@ static void stl_sc26198disableintrs(stlport_t *portp)
        printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        portp->imr = 0;
        stl_sc26198setreg(portp, IMR, 0);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4637,8 +4595,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len)
        printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len);
 #endif
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        if (len == 1) {
                stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK);
@@ -4647,7 +4604,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len)
                stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK);
        }
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4672,8 +4629,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state)
        if (tty == (struct tty_struct *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
 
        if (state) {
@@ -4719,7 +4675,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state)
        }
 
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4744,8 +4700,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state)
        if (tty == (struct tty_struct *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        if (state) {
                mr0 = stl_sc26198getreg(portp, MR0);
@@ -4765,7 +4720,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state)
                stl_sc26198setreg(portp, MR0, mr0);
        }
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4781,14 +4736,13 @@ static void stl_sc26198flush(stlport_t *portp)
        if (portp == (stlport_t *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        stl_sc26198setreg(portp, SCCR, CR_TXRESET);
        stl_sc26198setreg(portp, SCCR, portp->crenable);
        BRDDISABLE(portp->brdnr);
        portp->tx.tail = portp->tx.head;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 /*****************************************************************************/
@@ -4815,12 +4769,11 @@ static int stl_sc26198datastate(stlport_t *portp)
        if (test_bit(ASYI_TXBUSY, &portp->istate))
                return 1;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&brd_lock, flags);
        BRDENABLE(portp->brdnr, portp->pagenr);
        sr = stl_sc26198getreg(portp, SR);
        BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&brd_lock, flags);
 
        return (sr & SR_TXEMPTY) ? 0 : 1;
 }
@@ -4878,6 +4831,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
        stlport_t       *portp;
        unsigned int    iack;
 
+       spin_lock(&brd_lock);
+
 /* 
  *     Work around bug in sc26198 chip... Cannot have A6 address
  *     line of UART high, else iack will be returned as 0.
@@ -4893,6 +4848,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
                stl_sc26198txisr(portp);
        else
                stl_sc26198otherisr(portp, iack);
+
+       spin_unlock(&brd_lock);
 }
 
 /*****************************************************************************/
index 3b4747230270a3dc38fbdcc12fab013ee5a23439..76b9107f7f814b53bda55814e3d5e8d890b02b44 100644 (file)
@@ -2320,7 +2320,7 @@ static int sx_init_portstructs (int nboards, int nports)
 #ifdef NEW_WRITE_LOCKING
                        port->gs.port_write_mutex = MUTEX;
 #endif
-                       port->gs.driver_lock = SPIN_LOCK_UNLOCKED;
+                       spin_lock_init(&port->gs.driver_lock);
                        /*
                         * Initializing wait queue
                         */
index 079db5a935a1210520d332071d6a47611182dfa4..f7802e5bd7ca757069e91beabf09c1cb4017222c 100644 (file)
@@ -56,7 +56,6 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 #include <linux/bitops.h>
-#include <linux/devfs_fs_kernel.h>     /* DevFs support */
 #include <linux/parport.h>             /* Our code depend on parport */
 #include <linux/device.h>
 
@@ -443,12 +442,6 @@ tipar_register(int nr, struct parport *port)
 
        class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
                        TIPAR_MINOR + nr), NULL, "par%d", nr);
-       /* Use devfs, tree: /dev/ticables/par/[0..2] */
-       err = devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr),
-                       S_IFCHR | S_IRUGO | S_IWUGO,
-                       "ticables/par/%d", nr);
-       if (err)
-               goto out_class;
 
        /* Display informations */
        pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
@@ -460,11 +453,7 @@ tipar_register(int nr, struct parport *port)
                pr_info("tipar%d: link cable not found\n", nr);
 
        err = 0;
-       goto out;
 
-out_class:
-       class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr));
-       class_destroy(tipar_class);
 out:
        return err;
 }
@@ -507,9 +496,6 @@ tipar_init_module(void)
                goto out;
        }
 
-       /* Use devfs with tree: /dev/ticables/par/[0..2] */
-       devfs_mk_dir("ticables/par");
-
        tipar_class = class_create(THIS_MODULE, "ticables");
        if (IS_ERR(tipar_class)) {
                err = PTR_ERR(tipar_class);
@@ -528,7 +514,6 @@ out_class:
        class_destroy(tipar_class);
 
 out_chrdev:
-       devfs_remove("ticables/par");
        unregister_chrdev(TIPAR_MAJOR, "tipar");
 out:
        return err;     
@@ -549,10 +534,8 @@ tipar_cleanup_module(void)
                        continue;
                parport_unregister_device(table[i].dev);
                class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
-               devfs_remove("ticables/par/%d", i);
        }
        class_destroy(tipar_class);
-       devfs_remove("ticables/par");
 
        pr_info("tipar: module unloaded\n");
 }
index 8b2a5996986819b62eccb4ffdb436d1d3903521a..a1143238fecabb28e844717346b7aefa88307318 100644 (file)
 #include <linux/kbd_kern.h>
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
-#include <linux/devfs_fs_kernel.h>
 
 #include <linux/kmod.h>
 
@@ -267,7 +266,6 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
        p->used = 0;
        p->size = size;
        p->next = NULL;
-       p->active = 0;
        p->commit = 0;
        p->read = 0;
        p->char_buf_ptr = (char *)(p->data);
@@ -327,10 +325,9 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
        /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
           remove this conditional if its worth it. This would be invisible
           to the callers */
-       if ((b = tty->buf.tail) != NULL) {
+       if ((b = tty->buf.tail) != NULL)
                left = b->size - b->used;
-               b->active = 1;
-       } else
+       else
                left = 0;
 
        if (left < size) {
@@ -338,12 +335,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
                if ((n = tty_buffer_find(tty, size)) != NULL) {
                        if (b != NULL) {
                                b->next = n;
-                               b->active = 0;
                                b->commit = b->used;
                        } else
                                tty->buf.head = n;
                        tty->buf.tail = n;
-                       n->active = 1;
                } else
                        size = left;
        }
@@ -404,10 +399,8 @@ void tty_schedule_flip(struct tty_struct *tty)
 {
        unsigned long flags;
        spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL) {
-               tty->buf.tail->active = 0;
+       if (tty->buf.tail != NULL)
                tty->buf.tail->commit = tty->buf.tail->used;
-       }
        spin_unlock_irqrestore(&tty->buf.lock, flags);
        schedule_delayed_work(&tty->buf.work, 1);
 }
@@ -784,11 +777,8 @@ restart:
        }
 
        clear_bit(TTY_LDISC, &tty->flags);
-       clear_bit(TTY_DONT_FLIP, &tty->flags);
-       if (o_tty) {
+       if (o_tty)
                clear_bit(TTY_LDISC, &o_tty->flags);
-               clear_bit(TTY_DONT_FLIP, &o_tty->flags);
-       }
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 
        /*
@@ -1955,7 +1945,6 @@ static void release_dev(struct file * filp)
         * race with the set_ldisc code path.
         */
        clear_bit(TTY_LDISC, &tty->flags);
-       clear_bit(TTY_DONT_FLIP, &tty->flags);
        cancel_delayed_work(&tty->buf.work);
 
        /*
@@ -2621,10 +2610,9 @@ int tty_ioctl(struct inode * inode, struct file * file,
                        tty->driver->break_ctl(tty, 0);
                        return 0;
                case TCSBRK:   /* SVID version: non-zero arg --> no break */
-                       /*
-                        * XXX is the above comment correct, or the
-                        * code below correct?  Is this ioctl used at
-                        * all by anyone?
+                       /* non-zero arg means wait for all output data
+                        * to be sent (performed above) but don't send break.
+                        * This is used by the tcdrain() termios function.
                         */
                        if (!arg)
                                return send_break(tty, 250);
@@ -2776,8 +2764,7 @@ static void flush_to_ldisc(void *private_)
        struct tty_struct *tty = (struct tty_struct *) private_;
        unsigned long   flags;
        struct tty_ldisc *disc;
-       struct tty_buffer *tbuf;
-       int count;
+       struct tty_buffer *tbuf, *head;
        char *char_buf;
        unsigned char *flag_buf;
 
@@ -2785,32 +2772,37 @@ static void flush_to_ldisc(void *private_)
        if (disc == NULL)       /*  !TTY_LDISC */
                return;
 
-       if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-               /*
-                * Do it after the next timer tick:
-                */
-               schedule_delayed_work(&tty->buf.work, 1);
-               goto out;
-       }
        spin_lock_irqsave(&tty->buf.lock, flags);
-       while((tbuf = tty->buf.head) != NULL) {
-               while ((count = tbuf->commit - tbuf->read) != 0) {
-                       char_buf = tbuf->char_buf_ptr + tbuf->read;
-                       flag_buf = tbuf->flag_buf_ptr + tbuf->read;
-                       tbuf->read += count;
+       head = tty->buf.head;
+       if (head != NULL) {
+               tty->buf.head = NULL;
+               for (;;) {
+                       int count = head->commit - head->read;
+                       if (!count) {
+                               if (head->next == NULL)
+                                       break;
+                               tbuf = head;
+                               head = head->next;
+                               tty_buffer_free(tty, tbuf);
+                               continue;
+                       }
+                       if (!tty->receive_room) {
+                               schedule_delayed_work(&tty->buf.work, 1);
+                               break;
+                       }
+                       if (count > tty->receive_room)
+                               count = tty->receive_room;
+                       char_buf = head->char_buf_ptr + head->read;
+                       flag_buf = head->flag_buf_ptr + head->read;
+                       head->read += count;
                        spin_unlock_irqrestore(&tty->buf.lock, flags);
                        disc->receive_buf(tty, char_buf, flag_buf, count);
                        spin_lock_irqsave(&tty->buf.lock, flags);
                }
-               if (tbuf->active)
-                       break;
-               tty->buf.head = tbuf->next;
-               if (tty->buf.head == NULL)
-                       tty->buf.tail = NULL;
-               tty_buffer_free(tty, tbuf);
+               tty->buf.head = head;
        }
        spin_unlock_irqrestore(&tty->buf.lock, flags);
-out:
+
        tty_ldisc_deref(disc);
 }
 
@@ -2903,10 +2895,8 @@ void tty_flip_buffer_push(struct tty_struct *tty)
 {
        unsigned long flags;
        spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL) {
-               tty->buf.tail->active = 0;
+       if (tty->buf.tail != NULL)
                tty->buf.tail->commit = tty->buf.tail->used;
-       }
        spin_unlock_irqrestore(&tty->buf.lock, flags);
 
        if (tty->low_latency)
@@ -2964,8 +2954,8 @@ static struct class *tty_class;
  * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error).
  *
  * This call is required to be made to register an individual tty device if
- * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set.  If that
- * bit is not set, this function should not be called.
+ * the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set.  If that
+ * bit is not set, this function should not be called by a tty driver.
  */
 struct class_device *tty_register_device(struct tty_driver *driver,
                                         unsigned index, struct device *device)
@@ -2979,9 +2969,6 @@ struct class_device *tty_register_device(struct tty_driver *driver,
                return ERR_PTR(-EINVAL);
        }
 
-       devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
-                       "%s%d", driver->devfs_name, index + driver->name_base);
-
        if (driver->type == TTY_DRIVER_TYPE_PTY)
                pty_line_name(driver, index, name);
        else
@@ -3000,7 +2987,6 @@ struct class_device *tty_register_device(struct tty_driver *driver,
  */
 void tty_unregister_device(struct tty_driver *driver, unsigned index)
 {
-       devfs_remove("%s%d", driver->devfs_name, index + driver->name_base);
        class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index);
 }
 
@@ -3122,7 +3108,7 @@ int tty_register_driver(struct tty_driver *driver)
        
        list_add(&driver->tty_drivers, &tty_drivers);
        
-       if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
+       if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) {
                for(i = 0; i < driver->num; i++)
                    tty_register_device(driver, i, NULL);
        }
@@ -3165,7 +3151,7 @@ int tty_unregister_driver(struct tty_driver *driver)
                        driver->termios_locked[i] = NULL;
                        kfree(tp);
                }
-               if (!(driver->flags & TTY_DRIVER_NO_DEVFS))
+               if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
                        tty_unregister_device(driver, i);
        }
        p = driver->ttys;
@@ -3241,14 +3227,12 @@ static int __init tty_init(void)
        if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
            register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
                panic("Couldn't register /dev/tty driver\n");
-       devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty");
        class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
 
        cdev_init(&console_cdev, &console_fops);
        if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
            register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
                panic("Couldn't register /dev/console driver\n");
-       devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console");
        class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console");
 
 #ifdef CONFIG_UNIX98_PTYS
@@ -3256,7 +3240,6 @@ static int __init tty_init(void)
        if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
            register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
                panic("Couldn't register /dev/ptmx driver\n");
-       devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx");
        class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
 #endif
 
@@ -3265,7 +3248,6 @@ static int __init tty_init(void)
        if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
            register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
                panic("Couldn't register /dev/tty0 driver\n");
-       devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0");
        class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
 
        vty_init();
index 3c1dafaa3441eacbeae9e2f924219fd5fea5e5fe..234d7f3fb114e161fde4aa7de491325e446db384 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/tty.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
@@ -478,12 +477,6 @@ static struct class *vc_class;
 
 void vcs_make_devfs(struct tty_struct *tty)
 {
-       devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 1),
-                       S_IFCHR|S_IRUSR|S_IWUSR,
-                       "vcc/%u", tty->index + 1);
-       devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129),
-                       S_IFCHR|S_IRUSR|S_IWUSR,
-                       "vcc/a%u", tty->index + 1);
        class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1),
                        NULL, "vcs%u", tty->index + 1);
        class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129),
@@ -491,8 +484,6 @@ void vcs_make_devfs(struct tty_struct *tty)
 }
 void vcs_remove_devfs(struct tty_struct *tty)
 {
-       devfs_remove("vcc/%u", tty->index + 1);
-       devfs_remove("vcc/a%u", tty->index + 1);
        class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1));
        class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129));
 }
@@ -503,8 +494,6 @@ int __init vcs_init(void)
                panic("unable to get major %d for vcs device", VCS_MAJOR);
        vc_class = class_create(THIS_MODULE, "vc");
 
-       devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0");
-       devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0");
        class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
        class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
        return 0;
index 4e5360388748e7facd991ceefe64a06439f3b35c..07f5ce4b28e368672ec52f161abd3b5ed6606a34 100644 (file)
@@ -1152,7 +1152,6 @@ static int __init viocons_init2(void)
        viotty_driver = alloc_tty_driver(VTTY_PORTS);
        viotty_driver->owner = THIS_MODULE;
        viotty_driver->driver_name = "vioconsole";
-       viotty_driver->devfs_name = "vcs/";
        viotty_driver->name = "tty";
        viotty_driver->name_base = 1;
        viotty_driver->major = TTY_MAJOR;
index 11c7e9de595862a9747b6b19b18d0499e357da6b..198f1505ae238fac3396ddff561e1c5c2834b7fc 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/fs.h>
 #include <linux/cdev.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/major.h>
 #include <linux/completion.h>
 #include <linux/proc_fs.h>
@@ -246,7 +245,6 @@ static struct device *tape_device[VIOTAPE_MAX_TAPE];
  */
 static struct {
        unsigned char   cur_part;
-       int             dev_handle;
        unsigned char   part_stat_rwi[MAX_PARTITIONS];
 } state[VIOTAPE_MAX_TAPE];
 
@@ -959,12 +957,7 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
                        "iseries!vt%d", i);
        class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
                        NULL, "iseries!nvt%d", i);
-       devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR,
-                       "iseries/vt%d", i);
-       devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i | 0x80),
-                       S_IFCHR | S_IRUSR | S_IWUSR, "iseries/nvt%d", i);
        sprintf(tapename, "iseries/vt%d", i);
-       state[i].dev_handle = devfs_register_tape(tapename);
        printk(VIOTAPE_KERN_INFO "tape %s is iSeries "
                        "resource %10.10s type %4.4s, model %3.3s\n",
                        tapename, viotape_unitinfo[i].rsrcname,
@@ -976,9 +969,6 @@ static int viotape_remove(struct vio_dev *vdev)
 {
        int i = vdev->unit_address;
 
-       devfs_remove("iseries/nvt%d", i);
-       devfs_remove("iseries/vt%d", i);
-       devfs_unregister_tape(state[i].dev_handle);
        class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
        class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
        return 0;
index fd00822ac145ea50f224321874a107d67cfb670c..fe99fc1aba45c9d3978693dbb12dba5a6e330c76 100644 (file)
@@ -147,7 +147,6 @@ static int scc_init_drivers(void)
        scc_driver->owner = THIS_MODULE;
        scc_driver->driver_name = "scc";
        scc_driver->name = "ttyS";
-       scc_driver->devfs_name = "tts/";
        scc_driver->major = TTY_MAJOR;
        scc_driver->minor_start = SCC_MINOR_BASE;
        scc_driver->type = TTY_DRIVER_TYPE_SERIAL;
index 05e6e814d86fd64d4670dccd38fe8e1eb7132138..073da48c092e0ae804cc6354b9c897c668b6033c 100644 (file)
@@ -689,9 +689,9 @@ static int __devinit giu_probe(struct platform_device *dev)
 
        for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
                if (i < GIU_IRQ(GIUINT_HIGH_OFFSET))
-                       irq_desc[i].handler = &giuint_low_irq_type;
+                       irq_desc[i].chip = &giuint_low_irq_type;
                else
-                       irq_desc[i].handler = &giuint_high_irq_type;
+                       irq_desc[i].chip = &giuint_high_irq_type;
        }
 
        return cascade_irq(GIUINT_IRQ, giu_get_irq);
index 714d95ff2f1e462fe36c881a17a7fb61ea5414a9..d6f65032649ab83398407026accffa8c9071ffdd 100644 (file)
@@ -79,7 +79,6 @@
 #include <linux/mm.h>
 #include <linux/console.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
 #include <linux/tiocl.h>
@@ -2663,7 +2662,6 @@ int __init vty_init(void)
        if (!console_driver)
                panic("Couldn't allocate console driver\n");
        console_driver->owner = THIS_MODULE;
-       console_driver->devfs_name = "vc/";
        console_driver->name = "tty";
        console_driver->name_base = 1;
        console_driver->major = TTY_MAJOR;
index ac83bc4b019adabb47c21081e7b2b1ca2b485ca6..00080655533d338ae6438b8b3d37c4707f125fff 100644 (file)
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/platform_device.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
 
-#define WDT_DEFAULT_TIME       5       /* seconds */
-#define WDT_MAX_TIME           256     /* 256 seconds */
+#define WDT_DEFAULT_TIME       5       /* seconds */
+#define WDT_MAX_TIME           256     /* seconds */
 
 static int wdt_time = WDT_DEFAULT_TIME;
 static int nowayout = WATCHDOG_NOWAYOUT;
@@ -32,8 +33,10 @@ static int nowayout = WATCHDOG_NOWAYOUT;
 module_param(wdt_time, int, 0);
 MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+#endif
 
 
 static unsigned long at91wdt_busy;
@@ -138,7 +141,7 @@ static int at91_wdt_ioctl(struct inode *inode, struct file *file,
                case WDIOC_SETTIMEOUT:
                        if (get_user(new_value, p))
                                return -EFAULT;
-                               
+
                        if (at91_wdt_settimeout(new_value))
                                return -EINVAL;
 
@@ -196,27 +199,84 @@ static struct miscdevice at91wdt_miscdev = {
        .fops           = &at91wdt_fops,
 };
 
-static int __init at91_wdt_init(void)
+static int __init at91wdt_probe(struct platform_device *pdev)
 {
        int res;
 
-       /* Check that the heartbeat value is within range; if not reset to the default */
-       if (at91_wdt_settimeout(wdt_time)) {
-               at91_wdt_settimeout(WDT_DEFAULT_TIME);
-               printk(KERN_INFO "at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
-       }
+       if (at91wdt_miscdev.dev)
+               return -EBUSY;
+       at91wdt_miscdev.dev = &pdev->dev;
 
        res = misc_register(&at91wdt_miscdev);
        if (res)
                return res;
 
-       printk("AT91 Watchdog Timer enabled (%d seconds, nowayout=%d)\n", wdt_time, nowayout);
+       printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : "");
        return 0;
 }
 
+static int __exit at91wdt_remove(struct platform_device *pdev)
+{
+       int res;
+
+       res = misc_deregister(&at91wdt_miscdev);
+       if (!res)
+               at91wdt_miscdev.dev = NULL;
+
+       return res;
+}
+
+static void at91wdt_shutdown(struct platform_device *pdev)
+{
+       at91_wdt_stop();
+}
+
+#ifdef CONFIG_PM
+
+static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+       at91_wdt_stop();
+       return 0;
+}
+
+static int at91wdt_resume(struct platform_device *pdev)
+{
+       if (at91wdt_busy)
+               at91_wdt_start();
+               return 0;
+}
+
+#else
+#define at91wdt_suspend NULL
+#define at91wdt_resume NULL
+#endif
+
+static struct platform_driver at91wdt_driver = {
+       .probe          = at91wdt_probe,
+       .remove         = __exit_p(at91wdt_remove),
+       .shutdown       = at91wdt_shutdown,
+       .suspend        = at91wdt_suspend,
+       .resume         = at91wdt_resume,
+       .driver         = {
+               .name   = "at91_wdt",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init at91_wdt_init(void)
+{
+       /* Check that the heartbeat value is within range; if not reset to the default */
+       if (at91_wdt_settimeout(wdt_time)) {
+               at91_wdt_settimeout(WDT_DEFAULT_TIME);
+               pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
+       }
+
+       return platform_driver_register(&at91wdt_driver);
+}
+
 static void __exit at91_wdt_exit(void)
 {
-       misc_deregister(&at91wdt_miscdev);
+       platform_driver_unregister(&at91wdt_driver);
 }
 
 module_init(at91_wdt_init);
index fa2ba9ebe42aacf3478212143547c460d877402e..bfbdbbf3c2f279a6fa2027e9837bbb4d539e6818 100644 (file)
@@ -205,6 +205,23 @@ static int tco_timer_set_heartbeat (int t)
        return 0;
 }
 
+static int tco_timer_get_timeleft (int *time_left)
+{
+       unsigned char val;
+
+       spin_lock(&tco_lock);
+
+       /* read the TCO Timer */
+       val = inb (TCO1_RLD);
+       val &= 0x3f;
+
+       spin_unlock(&tco_lock);
+
+       *time_left = (int)((val * 6) / 10);
+
+       return 0;
+}
+
 /*
  *     /dev/watchdog handling
  */
@@ -272,6 +289,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
 {
        int new_options, retval = -EINVAL;
        int new_heartbeat;
+       int time_left;
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
        static struct watchdog_info ident = {
@@ -320,7 +338,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
                                return -EFAULT;
 
                        if (tco_timer_set_heartbeat(new_heartbeat))
-                           return -EINVAL;
+                               return -EINVAL;
 
                        tco_timer_keepalive ();
                        /* Fall */
@@ -329,6 +347,14 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
                case WDIOC_GETTIMEOUT:
                        return put_user(heartbeat, p);
 
+               case WDIOC_GETTIMELEFT:
+               {
+                       if (tco_timer_get_timeleft(&time_left))
+                               return -EINVAL;
+
+                       return put_user(time_left, p);
+               }
+
                default:
                        return -ENOIOCTLCMD;
        }
index 2451edbefece8ab448a5ece121a1a35ee70f87fc..1f40ecefbf7260c020c6117118975a0facfadff6 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 /*
- *     A bells and whistles driver is available from: 
+ *     A bells and whistles driver is available from:
  *     http://www.kernel.org/pub/linux/kernel/people/wim/pcwd/pcwd_pci/
  *
  *     More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
@@ -390,6 +390,24 @@ static int pcipcwd_get_temperature(int *temperature)
        return 0;
 }
 
+static int pcipcwd_get_timeleft(int *time_left)
+{
+       int msb;
+       int lsb;
+
+       /* Read the time that's left before rebooting */
+       /* Note: if the board is not yet armed then we will read 0xFFFF */
+       send_command(CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
+
+       *time_left = (msb << 8) + lsb;
+
+       if (debug >= VERBOSE)
+               printk(KERN_DEBUG PFX "Time left before next reboot: %d\n",
+                      *time_left);
+
+       return 0;
+}
+
 /*
  *     /dev/watchdog handling
  */
@@ -512,6 +530,16 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
                case WDIOC_GETTIMEOUT:
                        return put_user(heartbeat, p);
 
+               case WDIOC_GETTIMELEFT:
+               {
+                       int time_left;
+
+                       if (pcipcwd_get_timeleft(&time_left))
+                               return -EFAULT;
+
+                       return put_user(time_left, p);
+               }
+
                default:
                        return -ENOIOCTLCMD;
        }
index 3fdfda9324fae46a3429f3191354ee4ffec4c2cf..0d072bed501dfd744796e62a58d7468060e78f55 100644 (file)
@@ -317,6 +317,19 @@ static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd, int *temp
        return 0;
 }
 
+static int usb_pcwd_get_timeleft(struct usb_pcwd_private *usb_pcwd, int *time_left)
+{
+       unsigned char msb, lsb;
+
+       /* Read the time that's left before rebooting */
+       /* Note: if the board is not yet armed then we will read 0xFFFF */
+       usb_pcwd_send_command(usb_pcwd, CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
+
+       *time_left = (msb << 8) + lsb;
+
+       return 0;
+}
+
 /*
  *     /dev/watchdog handling
  */
@@ -422,6 +435,16 @@ static int usb_pcwd_ioctl(struct inode *inode, struct file *file,
                case WDIOC_GETTIMEOUT:
                        return put_user(heartbeat, p);
 
+               case WDIOC_GETTIMELEFT:
+               {
+                       int time_left;
+
+                       if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left))
+                               return -EFAULT;
+
+                       return put_user(time_left, p);
+               }
+
                default:
                        return -ENOIOCTLCMD;
        }
index 44d1eca83a7250748bf27c637998c3c2973f9657..35e0b9ceecf7faa90f9ab34784112533e7d48ec7 100644 (file)
@@ -1497,6 +1497,7 @@ int cpufreq_update_policy(unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
 
+#ifdef CONFIG_HOTPLUG_CPU
 static int cpufreq_cpu_callback(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
@@ -1532,10 +1533,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpufreq_cpu_notifier =
+static struct notifier_block __cpuinitdata cpufreq_cpu_notifier =
 {
     .notifier_call = cpufreq_cpu_callback,
 };
+#endif /* CONFIG_HOTPLUG_CPU */
 
 /*********************************************************************
  *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
@@ -1596,7 +1598,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
        }
 
        if (!ret) {
-               register_cpu_notifier(&cpufreq_cpu_notifier);
+               register_hotcpu_notifier(&cpufreq_cpu_notifier);
                dprintk("driver %s up and running\n", driver_data->name);
                cpufreq_debug_enable_ratelimit();
        }
@@ -1628,7 +1630,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
        dprintk("unregistering driver %s\n", driver->name);
 
        sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
-       unregister_cpu_notifier(&cpufreq_cpu_notifier);
+       unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
 
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
        cpufreq_driver = NULL;
index c576c0b3f452629560fd2567a1bc5735011daf92..145061b8472a814b96e1075e51876ecbb5f3f246 100644 (file)
@@ -350,7 +350,7 @@ __init cpufreq_stats_init(void)
                return ret;
        }
 
-       register_cpu_notifier(&cpufreq_stat_cpu_notifier);
+       register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
        lock_cpu_hotplug();
        for_each_online_cpu(cpu) {
                cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE,
@@ -368,7 +368,7 @@ __exit cpufreq_stats_exit(void)
                        CPUFREQ_POLICY_NOTIFIER);
        cpufreq_unregister_notifier(&notifier_trans_block,
                        CPUFREQ_TRANSITION_NOTIFIER);
-       unregister_cpu_notifier(&cpufreq_stat_cpu_notifier);
+       unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
        lock_cpu_hotplug();
        for_each_online_cpu(cpu) {
                cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD,
index 3e0d04d5a800b574579bbd2cecf06c6b24fc66a5..8b46ef7d9ff8365b9fda3dc8bc439a6654c90dca 100644 (file)
@@ -488,7 +488,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
                dev_err(&dev->dev, "SMBus base address uninitialized, "
                        "upgrade BIOS\n");
                err = -ENODEV;
-               goto exit_disable;
+               goto exit;
        }
 
        err = pci_request_region(dev, SMBBAR, i801_driver.name);
@@ -496,7 +496,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
                dev_err(&dev->dev, "Failed to request SMBus region "
                        "0x%lx-0x%lx\n", i801_smba,
                        pci_resource_end(dev, SMBBAR));
-               goto exit_disable;
+               goto exit;
        }
 
        pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
@@ -520,11 +520,12 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
        err = i2c_add_adapter(&i801_adapter);
        if (err) {
                dev_err(&dev->dev, "Failed to add SMBus adapter\n");
-               goto exit_disable;
+               goto exit_release;
        }
+       return 0;
 
-exit_disable:
-       pci_disable_device(dev);
+exit_release:
+       pci_release_region(dev, SMBBAR);
 exit:
        return err;
 }
@@ -533,7 +534,10 @@ static void __devexit i801_remove(struct pci_dev *dev)
 {
        i2c_del_adapter(&i801_adapter);
        pci_release_region(dev, SMBBAR);
-       pci_disable_device(dev);
+       /*
+        * do not call pci_disable_device(dev) since it can cause hard hangs on
+        * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
+        */
 }
 
 static struct pci_driver i801_driver = {
index d633081fa4c58123bc8769e7439af651039cb415..d1266fe2d1abc9b53277c9719019cd97f632cfd2 100644 (file)
@@ -774,11 +774,18 @@ config BLK_DEV_IDEDMA_PMAC
          performance.
 
 config BLK_DEV_IDE_PMAC_BLINK
-       bool "Blink laptop LED on drive activity"
+       bool "Blink laptop LED on drive activity (DEPRECATED)"
        depends on BLK_DEV_IDE_PMAC && ADB_PMU
+       select ADB_PMU_LED
+       select LEDS_TRIGGERS
+       select LEDS_TRIGGER_IDE_DISK
        help
          This option enables the use of the sleep LED as a hard drive
          activity LED.
+         This option is deprecated, it only selects ADB_PMU_LED and
+         LEDS_TRIGGER_IDE_DISK and changes the code in the new led class
+         device to default to the ide-disk trigger (which should be set
+         from userspace via sysfs).
 
 config BLK_DEV_IDE_SWARM
        tristate "IDE for Sibyte evaluation boards"
index 99fa42402e71ee7f373a335c928ed1218c73ffd6..bfafd4846a08024f1b470de94bc52d5f1793365d 100644 (file)
@@ -3527,8 +3527,6 @@ static int ide_cd_probe(ide_drive_t *drive)
        drive->driver_data = info;
 
        g->minors = 1;
-       snprintf(g->devfs_name, sizeof(g->devfs_name),
-                       "%s/cd", drive->devfs_name);
        g->driverfs_dev = &drive->gendev;
        g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
        if (ide_cdrom_setup(drive)) {
index f033d732f387277fbabe2fe7bb4123afe371a9d8..d0227c39ced16d763c9242f85ee77415ddb36040 100644 (file)
@@ -1018,7 +1018,6 @@ static void ide_disk_release(struct kref *kref)
        struct gendisk *g = idkp->disk;
 
        drive->driver_data = NULL;
-       drive->devfs_name[0] = '\0';
        g->private_data = NULL;
        put_disk(g);
        kfree(idkp);
@@ -1222,7 +1221,6 @@ static int ide_disk_probe(ide_drive_t *drive)
                drive->attach = 1;
 
        g->minors = 1 << PARTN_BITS;
-       strcpy(g->devfs_name, drive->devfs_name);
        g->driverfs_dev = &drive->gendev;
        g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
        set_capacity(g, idedisk_capacity(drive));
index 4656587aa2f70d2e1deced9716664f89162f7f91..68628327c0f55ce9c33e6938d350e4de09c702a1 100644 (file)
@@ -2176,7 +2176,6 @@ static int ide_floppy_probe(ide_drive_t *drive)
 
        g->minors = 1 << PARTN_BITS;
        g->driverfs_dev = &drive->gendev;
-       strcpy(g->devfs_name, drive->devfs_name);
        g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
        g->fops = &idefloppy_ops;
        drive->attach = 1;
index 935cb2583770fa567c7c531dbda03d5d0f935985..26ceab1e90bb5d94f71100e6239349343cd849cc 100644 (file)
@@ -505,7 +505,7 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8
                }
        }
 
-       if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
+       if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ && hwif->err_stops_fifo == 0)
                try_to_flush_leftover_data(drive);
 
        if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
index 97a49e77a8f1f5d30d906847f202ad85ea2f08c8..32117f0ec5c00727f41fde8e0765d85449a4652b 100644 (file)
@@ -597,6 +597,10 @@ u8 eighty_ninty_three (ide_drive_t *drive)
 {
        if(HWIF(drive)->udma_four == 0)
                return 0;
+
+       /* Check for SATA but only if we are ATA5 or higher */
+       if (drive->id->hw_config == 0 && (drive->id->major_rev_num & 0x7FE0))
+               return 1;
        if (!(drive->id->hw_config & 0x6000))
                return 0;
 #ifndef CONFIG_IDEDMA_IVB
index 9ebf8ae2a5e30676d83369c32a8aa6c5546fed84..0d5038a2856060ac369bd7f61195e449e79758b7 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/spinlock.h>
 #include <linux/kmod.h>
 #include <linux/pci.h>
@@ -1279,10 +1278,6 @@ static void drive_release_dev (struct device *dev)
        ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
 
        spin_lock_irq(&ide_lock);
-       if (drive->devfs_name[0] != '\0') {
-               devfs_remove(drive->devfs_name);
-               drive->devfs_name[0] = '\0';
-       }
        ide_remove_drive_from_hwgroup(drive);
        kfree(drive->id);
        drive->id = NULL;
@@ -1316,12 +1311,6 @@ static void init_gendisk (ide_hwif_t *hwif)
                drive->gendev.bus = &ide_bus_type;
                drive->gendev.driver_data = drive;
                drive->gendev.release = drive_release_dev;
-               if (drive->present) {
-                       sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d",
-                               (hwif->channel && hwif->mate) ?
-                               hwif->mate->index : hwif->index,
-                               hwif->channel, unit, drive->lun);
-               }
        }
        blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
                        THIS_MODULE, ata_probe, ata_lock, hwif);
index 09f3a7dab28ade081cd5e0fe94120aaa96fc8e8d..4b91101e12b7715fee6682f6dcc8124006f672f6 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/major.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/slab.h>
@@ -4726,9 +4725,6 @@ static void ide_tape_release(struct kref *kref)
                        MKDEV(IDETAPE_MAJOR, tape->minor));
        class_device_destroy(idetape_sysfs_class,
                        MKDEV(IDETAPE_MAJOR, tape->minor + 128));
-       devfs_remove("%s/mt", drive->devfs_name);
-       devfs_remove("%s/mtn", drive->devfs_name);
-       devfs_unregister_tape(g->number);
        idetape_devs[tape->minor] = NULL;
        g->private_data = NULL;
        put_disk(g);
@@ -4902,14 +4898,6 @@ static int ide_tape_probe(ide_drive_t *drive)
        class_device_create(idetape_sysfs_class, NULL,
                        MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name);
 
-       devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor),
-                       S_IFCHR | S_IRUGO | S_IWUGO,
-                       "%s/mt", drive->devfs_name);
-       devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor + 128),
-                       S_IFCHR | S_IRUGO | S_IWUGO,
-                       "%s/mtn", drive->devfs_name);
-
-       g->number = devfs_register_tape(drive->devfs_name);
        g->fops = &idetape_block_ops;
        ide_register_region(g);
 
index 59fe358048b32ebebf029eb292f0cd960215352f..1cdf44205162cc79f347a45727e9261df4dbf53a 100644 (file)
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/completion.h>
 #include <linux/reboot.h>
 #include <linux/cdrom.h>
@@ -592,13 +591,8 @@ void ide_unregister(unsigned int index)
                goto abort;
        for (unit = 0; unit < MAX_DRIVES; ++unit) {
                drive = &hwif->drives[unit];
-               if (!drive->present) {
-                       if (drive->devfs_name[0] != '\0') {
-                               devfs_remove(drive->devfs_name);
-                               drive->devfs_name[0] = '\0';
-                       }
+               if (!drive->present)
                        continue;
-               }
                spin_unlock_irq(&ide_lock);
                device_unregister(&drive->gendev);
                wait_for_completion(&drive->gendev_rel_comp);
@@ -1996,7 +1990,6 @@ EXPORT_SYMBOL_GPL(ide_bus_type);
 static int __init ide_init(void)
 {
        printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
-       devfs_mk_dir("ide");
        system_bus_speed = ide_system_bus_speed();
 
        bus_register(&ide_bus_type);
@@ -2074,7 +2067,6 @@ void cleanup_module (void)
 #ifdef CONFIG_PROC_FS
        proc_ide_destroy();
 #endif
-       devfs_remove("ide");
 
        bus_unregister(&ide_bus_type);
 }
index c743e68c33aadca3894017ed2ba1c82cde5cff52..3edd7060510fa6e668e46cc6deb1000fe4c4fc69 100644 (file)
@@ -22,7 +22,7 @@ struct chipset_bus_clock_list_entry {
        u8 ultra_settings;
 };
 
-static struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
+static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
        {       XFER_UDMA_6,    0x31,   0x07    },
        {       XFER_UDMA_5,    0x31,   0x06    },
        {       XFER_UDMA_4,    0x31,   0x05    },
@@ -42,7 +42,7 @@ static struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
        {       0,              0x00,   0x00    }
 };
 
-static struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
+static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
        {       XFER_UDMA_6,    0x41,   0x06    },
        {       XFER_UDMA_5,    0x41,   0x05    },
        {       XFER_UDMA_4,    0x41,   0x04    },
@@ -254,7 +254,8 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
 
        if (dev->resource[PCI_ROM_RESOURCE].start) {
                pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
+                       (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
        }
 
        if (bus_speed <= 33)
@@ -425,12 +426,12 @@ static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_devi
        return d->init_setup(dev, d);
 }
 
-static struct pci_device_id aec62xx_pci_tbl[] = {
-       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
-       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
-       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
-       { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+static const struct pci_device_id aec62xx_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860), 1 },
+       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R), 2 },
+       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865), 3 },
+       { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R), 4 },
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
index 6e9dbf4d80775b4ab8ebfdeb018b7a0509b7865a..85007cb12c52356eaf7cab09b8d972e3441f5a8c 100644 (file)
@@ -75,6 +75,7 @@ static struct amd_ide_chip {
        { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE,        0x50, AMD_UDMA_133 },
        { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE,        0x50, AMD_UDMA_133 },
        { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE,        0x50, AMD_UDMA_133 },
+       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE,        0x50, AMD_UDMA_133 },
        { PCI_DEVICE_ID_AMD_CS5536_IDE,                 0x40, AMD_UDMA_100 },
        { 0 }
 };
@@ -490,7 +491,8 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
        /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
        /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"),
        /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"),
-       /* 18 */ DECLARE_AMD_DEV("AMD5536"),
+       /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65"),
+       /* 19 */ DECLARE_AMD_DEV("AMD5536"),
 };
 
 static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
@@ -528,7 +530,8 @@ static struct pci_device_id amd74xx_pci_tbl[] = {
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 },
-       { PCI_VENDOR_ID_AMD,    PCI_DEVICE_ID_AMD_CS5536_IDE,           PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 },
+       { PCI_VENDOR_ID_AMD,    PCI_DEVICE_ID_AMD_CS5536_IDE,           PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19 },
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
index 3d9c7afc86950ad1660852bba5eb680199cde1b2..92b7b1549b1668249b6cdea1bfdac4083a418527 100644 (file)
@@ -189,14 +189,6 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
 
 #endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-/*
- * Registers and masks for easy access by drive index:
- */
-#if 0
-static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-#endif
-
 /*
  * This routine writes the prepared setup/active/recovery counts
  * for a drive into the cmd646 chipset registers to active them.
@@ -606,13 +598,6 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
        class_rev &= 0xff;
 
-#ifdef __i386__
-       if (dev->resource[PCI_ROM_RESOURCE].start) {
-               pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-       }
-#endif
-
        switch(dev->device) {
                case PCI_DEVICE_ID_CMD_643:
                        break;
index be334da7a7549b4fb44f82e59000450875c1abfb..7da550281cf23a112d61b6cc68d946ad0e540d19 100644 (file)
@@ -176,7 +176,7 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha
                        pci_write_config_dword(dev, PCI_ROM_ADDRESS,
                                dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
                        printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
-                               dev->resource[PCI_ROM_RESOURCE].start);
+                               (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
                }
                pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
        } else {
index acd63173199bbf17acd1a306da2160cda563c511..5a8334d134fbda2d1caebb0ab0ea4e93444f80e9 100644 (file)
@@ -313,8 +313,8 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
        if (dev->resource[PCI_ROM_RESOURCE].start) {
                pci_write_config_dword(dev, PCI_ROM_ADDRESS,
                        dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
-                       name, dev->resource[PCI_ROM_RESOURCE].start);
+               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
+                       (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
        }
 
 #ifdef CONFIG_PPC_PMAC
@@ -338,6 +338,8 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
        hwif->ultra_mask = 0x7f;
        hwif->mwdma_mask = 0x07;
 
+       hwif->err_stops_fifo = 1;
+
        hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
        hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
        hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
index 22d17548ecdbd273628c19c303cc914f8c5b25d3..1e209d8f9437f4e04199bc8b4365d4c48bd0f298 100644 (file)
@@ -101,31 +101,6 @@ static const char *pdc_quirk_drives[] = {
 #define        MC1             0x02    /* DMA"C" timing */
 #define        MC0             0x01    /* DMA"C" timing */
 
-#if 0
-       unsigned long bibma  = pci_resource_start(dev, 4);
-       u8 hi = 0, lo = 0;
-
-       u8 sc1c = inb_p((u16)bibma + 0x1c); 
-       u8 sc1e = inb_p((u16)bibma + 0x1e);
-       u8 sc1f = inb_p((u16)bibma + 0x1f);
-
-       p += sprintf(p, "Host Mode                            : %s\n",
-               (sc1f & 0x08) ? "Tri-Stated" : "Normal");
-       p += sprintf(p, "Bus Clocking                         : %s\n",
-               ((sc1f & 0xC0) == 0xC0) ? "100 External" :
-               ((sc1f & 0x80) == 0x80) ? "66 External" :
-               ((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
-       p += sprintf(p, "IO pad select                        : %s mA\n",
-               ((sc1c & 0x03) == 0x03) ? "10" :
-               ((sc1c & 0x02) == 0x02) ? "8" :
-               ((sc1c & 0x01) == 0x01) ? "6" :
-               ((sc1c & 0x00) == 0x00) ? "4" : "??");
-       hi = sc1e >> 4;
-       lo = sc1e & 0xf;
-       p += sprintf(p, "Status Polling Period                : %d\n", hi);
-       p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
-#endif
-
 static u8 pdc202xx_ratemask (ide_drive_t *drive)
 {
        u8 mode;
@@ -505,73 +480,20 @@ static void pdc202xx_reset (ide_drive_t *drive)
        
        pdc202xx_reset_host(hwif);
        pdc202xx_reset_host(mate);
-#if 0
-       /*
-        * FIXME: Have to kick all the drives again :-/
-        * What a pain in the ACE!
-        */
-       if (hwif->present) {
-               u16 hunit = 0;
-               for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
-                       ide_drive_t *hdrive = &hwif->drives[hunit];
-                       if (hdrive->present) {
-                               if (hwif->ide_dma_check)
-                                       hwif->ide_dma_check(hdrive);
-                               else
-                                       hwif->tuneproc(hdrive, 5);
-                       }
-               }
-       }
-       if (mate->present) {
-               u16 munit = 0;
-               for (munit = 0; munit < MAX_DRIVES; ++munit) {
-                       ide_drive_t *mdrive = &mate->drives[munit];
-                       if (mdrive->present) {
-                               if (mate->ide_dma_check) 
-                                       mate->ide_dma_check(mdrive);
-                               else
-                                       mate->tuneproc(mdrive, 5);
-                       }
-               }
-       }
-#else
        hwif->tuneproc(drive, 5);
-#endif
 }
 
-static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
+                                                       const char *name)
 {
+       /* This doesn't appear needed */
        if (dev->resource[PCI_ROM_RESOURCE].start) {
                pci_write_config_dword(dev, PCI_ROM_ADDRESS,
                        dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
-                       name, dev->resource[PCI_ROM_RESOURCE].start);
-       }
-
-       /*
-        * software reset -  this is required because the bios
-        * will set UDMA timing on if the hdd supports it. The
-        * user may want to turn udma off. A bug in the pdc20262
-        * is that it cannot handle a downgrade in timing from
-        * UDMA to DMA. Disk accesses after issuing a set
-        * feature command will result in errors. A software
-        * reset leaves the timing registers intact,
-        * but resets the drives.
-        */
-#if 0
-       if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
-           (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
-           (dev->device == PCI_DEVICE_ID_PROMISE_20263) ||
-           (dev->device == PCI_DEVICE_ID_PROMISE_20262)) {
-               unsigned long high_16   = pci_resource_start(dev, 4);
-               byte udma_speed_flag    = inb(high_16 + 0x001f);
-               outb(udma_speed_flag | 0x10, high_16 + 0x001f);
-               mdelay(100);
-               outb(udma_speed_flag & ~0x10, high_16 + 0x001f);
-               mdelay(2000);   /* 2 seconds ?! */
+               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
+                       (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
        }
 
-#endif
        return dev->irq;
 }
 
@@ -599,6 +521,8 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
        hwif->mwdma_mask = 0x07;
        hwif->swdma_mask = 0x07;
 
+       hwif->err_stops_fifo = 1;
+
        hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
        hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
        hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
@@ -687,19 +611,6 @@ static int __devinit init_setup_pdc202ata4(struct pci_dev *dev,
                                "mirror fixed.\n", d->name);
                }
        }
-
-#if 0
-        if (dev->device == PCI_DEVICE_ID_PROMISE_20262)
-        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
-             (tmp & e->mask) != e->val))
-
-        if (d->enablebits[0].reg != d->enablebits[1].reg) {
-                d->enablebits[0].reg    = d->enablebits[1].reg;
-                d->enablebits[0].mask   = d->enablebits[1].mask;
-                d->enablebits[0].val    = d->enablebits[1].val;
-        }
-#endif
-
        return ide_setup_pci_device(dev, d);
 }
 
@@ -714,22 +625,6 @@ static int __devinit init_setup_pdc20265(struct pci_dev *dev,
                        "attached to I2O RAID controller.\n");
                return -ENODEV;
        }
-
-#if 0
-        {
-                u8 pri = 0, sec = 0;
-
-        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
-             (tmp & e->mask) != e->val))
-
-        if (d->enablebits[0].reg != d->enablebits[1].reg) {
-                d->enablebits[0].reg    = d->enablebits[1].reg;
-                d->enablebits[0].mask   = d->enablebits[1].mask;
-                d->enablebits[0].val    = d->enablebits[1].val;
-        }
-        }
-#endif
-
        return ide_setup_pci_device(dev, d);
 }
 
index 24e21b2838c15028bd4f72c4a2305ddf0b7b54a3..778b82ae964de770e81acef1c00eb18e20f5f8b6 100644 (file)
@@ -395,7 +395,6 @@ static int sc1200_resume (struct pci_dev *dev)
 {
        ide_hwif_t      *hwif = NULL;
 
-printk("SC1200: resume\n");
        pci_set_power_state(dev, PCI_D0);       // bring chip back from sleep state
        dev->current_state = PM_EVENT_ON;
        pci_enable_device(dev);
@@ -405,7 +404,6 @@ printk("SC1200: resume\n");
        while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
                unsigned int            basereg, r, d, format;
                sc1200_saved_state_t    *ss = (sc1200_saved_state_t *)hwif->config_data;
-printk("%s: SC1200: resume\n", hwif->name);
 
                //
                // Restore timing registers:  this may be unnecessary if BIOS also does it
@@ -493,7 +491,7 @@ static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_devic
 }
 
 static struct pci_device_id sc1200_pci_tbl[] = {
-       { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
index 0d3073f4eab4e3d8e55f6c34af0fadd9f262e659..5100b827a935213dcd737703d928b150d96f6033 100644 (file)
@@ -123,11 +123,11 @@ static u8 svwks_csb_check (struct pci_dev *dev)
 }
 static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
-       u8 udma_modes[]         = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
-       u8 dma_modes[]          = { 0x77, 0x21, 0x20 };
-       u8 pio_modes[]          = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-       u8 drive_pci[]          = { 0x41, 0x40, 0x43, 0x42 };
-       u8 drive_pci2[]         = { 0x45, 0x44, 0x47, 0x46 };
+       static const u8 udma_modes[]            = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+       static const u8 dma_modes[]             = { 0x77, 0x21, 0x20 };
+       static const u8 pio_modes[]             = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+       static const u8 drive_pci[]             = { 0x41, 0x40, 0x43, 0x42 };
+       static const u8 drive_pci2[]            = { 0x45, 0x44, 0x47, 0x46 };
 
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
@@ -392,16 +392,6 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
                        }
                        outb_p(0x06, 0x0c00);
                        dev->irq = inb_p(0x0c01);
-#if 0
-                       printk("%s: device class (0x%04x)\n",
-                               name, dev->class);
-                       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
-                               dev->class &= ~0x000F0F00;
-               //              dev->class |= ~0x00000400;
-                               dev->class |= ~0x00010100;
-                               /**/
-                       }
-#endif
                } else {
                        struct pci_dev * findev = NULL;
                        u8 reg41 = 0;
@@ -452,7 +442,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
                pci_write_config_byte(dev, 0x5A, btr);
        }
 
-       return (dev->irq) ? dev->irq : 0;
+       return dev->irq;
 }
 
 static unsigned int __devinit ata66_svwks_svwks (ide_hwif_t *hwif)
@@ -500,11 +490,6 @@ static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
 
-       /* Per Specified Design by OEM, and ASIC Architect */
-       if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
-           (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
-               return 1;
-
        /* Server Works */
        if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
                return ata66_svwks_svwks (hwif);
@@ -517,10 +502,14 @@ static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
        if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
                return ata66_svwks_cobalt (hwif);
 
+       /* Per Specified Design by OEM, and ASIC Architect */
+       if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+           (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
+               return 1;
+
        return 0;
 }
 
-#undef CAN_SW_DMA
 static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
 {
        u8 dma_stat = 0;
@@ -537,9 +526,6 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
                hwif->ultra_mask = 0x3f;
 
        hwif->mwdma_mask = 0x07;
-#ifdef CAN_SW_DMA
-       hwif->swdma_mask = 0x07;
-#endif /* CAN_SW_DMA */
 
        hwif->autodma = 0;
 
@@ -562,8 +548,6 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
        hwif->drives[1].autodma = (dma_stat & 0x40);
        hwif->drives[0].autotune = (!(dma_stat & 0x20));
        hwif->drives[1].autotune = (!(dma_stat & 0x40));
-//     hwif->drives[0].autodma = hwif->autodma;
-//     hwif->drives[1].autodma = hwif->autodma;
 }
 
 /*
@@ -593,11 +577,6 @@ static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
                if (dev->resource[0].start == 0x01f1)
                        d->bootable = ON_BOARD;
        }
-#if 0
-       if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
-             (!(PCI_FUNC(dev->devfn) & 1)))
-               d->autodma = AUTODMA;
-#endif
 
        d->channels = ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
                        dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
@@ -671,11 +650,11 @@ static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device
 }
 
 static struct pci_device_id svwks_pci_tbl[] = {
-       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
-       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
-       { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 1},
+       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
+       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 3},
+       { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 4},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
index f1ca154dd52ca088f25ec0c0ac28845a47a59e18..72dade14c725996acc24af25143df12eb7449c63 100644 (file)
@@ -38,9 +38,6 @@
 
 #include <asm/io.h>
 
-#undef SIIMAGE_VIRTUAL_DMAPIO
-#undef SIIMAGE_LARGE_DMA
-
 /**
  *     pdev_is_sata            -       check if device is SATA
  *     @pdev:  PCI device to check
@@ -461,36 +458,6 @@ static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
        return 0;
 }
 
-#if 0
-/**
- *     siimage_mmio_ide_dma_count      -       DMA bytes done
- *     @drive
- *
- *     If we are doing VDMA the CMD680 requires a little bit
- *     of more careful handling and we have to read the counts
- *     off ourselves. For non VDMA life is normal.
- */
-static int siimage_mmio_ide_dma_count (ide_drive_t *drive)
-{
-#ifdef SIIMAGE_VIRTUAL_DMAPIO
-       struct request *rq      = HWGROUP(drive)->rq;
-       ide_hwif_t *hwif        = HWIF(drive);
-       u32 count               = (rq->nr_sectors * SECTOR_SIZE);
-       u32 rcount              = 0;
-       unsigned long addr      = siimage_selreg(hwif, 0x1C);
-
-       hwif->OUTL(count, addr);
-       rcount = hwif->INL(addr);
-
-       printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n",
-               drive->name, count, rcount, rq->nr_sectors);
-
-#endif /* SIIMAGE_VIRTUAL_DMAPIO */
-       return __ide_dma_count(drive);
-}
-#endif
-
 /**
  *     siimage_mmio_ide_dma_test_irq   -       check we caused an IRQ
  *     @drive: drive we are testing
@@ -512,12 +479,10 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
                        u32 sata_error = hwif->INL(SATA_ERROR_REG);
                        hwif->OUTL(sata_error, SATA_ERROR_REG);
                        watchdog = (sata_error & 0x00680000) ? 1 : 0;
-#if 1
                        printk(KERN_WARNING "%s: sata_error = 0x%08x, "
                                "watchdog = %d, %s\n",
                                drive->name, sata_error, watchdog,
                                __FUNCTION__);
-#endif
 
                } else {
                        watchdog = (ext_stat & 0x8000) ? 1 : 0;
@@ -863,7 +828,7 @@ static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const ch
  *     time.
  *
  *     The hardware supports buffered taskfiles and also some rather nice
- *     extended PRD tables. Unfortunately right now we don't.
+ *     extended PRD tables. For better SI3112 support use the libata driver
  */
 
 static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
@@ -900,9 +865,6 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
         *      so we can't currently use it sanely since we want to
         *      use LBA48 mode.
         */     
-//     base += 0x10;
-//     hwif->no_lba48 = 1;
-
        hw.io_ports[IDE_DATA_OFFSET]    = base;
        hw.io_ports[IDE_ERROR_OFFSET]   = base + 1;
        hw.io_ports[IDE_NSECTOR_OFFSET] = base + 2;
@@ -936,15 +898,8 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
 
                base = (unsigned long) addr;
 
-#ifdef SIIMAGE_LARGE_DMA
-/* Watch the brackets - even Ken and Dennis get some language design wrong */
-       hwif->dma_base                  = base + (ch ? 0x18 : 0x10);
-       hwif->dma_base2                 = base + (ch ? 0x08 : 0x00);
-       hwif->dma_prdtable              = hwif->dma_base2 + 4;
-#else /* ! SIIMAGE_LARGE_DMA */
        hwif->dma_base                  = base + (ch ? 0x08 : 0x00);
        hwif->dma_base2                 = base + (ch ? 0x18 : 0x10);
-#endif /* SIIMAGE_LARGE_DMA */
        hwif->mmio                      = 2;
 }
 
@@ -1052,9 +1007,16 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
        hwif->reset_poll = &siimage_reset_poll;
        hwif->pre_reset = &siimage_pre_reset;
 
-       if(is_sata(hwif))
+       if(is_sata(hwif)) {
+               static int first = 1;
+
                hwif->busproc   = &siimage_busproc;
 
+               if (first) {
+                       printk(KERN_INFO "siimage: For full SATA support you should use the libata sata_sil module.\n");
+                       first = 0;
+               }
+       }
        if (!hwif->dma_base) {
                hwif->drives[0].autotune = 1;
                hwif->drives[1].autotune = 1;
@@ -1121,10 +1083,10 @@ static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_devi
 }
 
 static struct pci_device_id siimage_pci_tbl[] = {
-       { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), 0},
 #ifdef CONFIG_BLK_DEV_IDE_SATA
-       { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-       { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+       { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112), 1},
+       { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA), 2},
 #endif
        { 0, },
 };
index 8a5c7b286b2b86dbf5d0e9c9c00ed8ef134541d4..900301e43818bee500a9884870be937a6e9d1f16 100644 (file)
@@ -447,7 +447,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
                printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
                       hwif->name, rev);
        } else {
-#ifdef CONFIG_BLK_DEV_IDEDMA
                dma_state |= 0x60;
 
                hwif->atapi_dma = 1;
@@ -468,7 +467,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
 
                if (hwif->mate)
                        hwif->serialized = hwif->mate->serialized = 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
        }
        hwif->OUTB(dma_state, hwif->dma_base + 2);
 }
@@ -489,7 +487,7 @@ static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_dev
 }
 
 static struct pci_device_id sl82c105_pci_tbl[] = {
-       { PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
index 5112c726633bafde6685d326b29a0f38c870b97b..0968f6bc669a5684b7ba3f3e0205a2e03e250400 100644 (file)
@@ -72,7 +72,8 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
        u16 master_data;
        u8 slave_data;
                                 /* ISP  RTC */
-       u8 timings[][2] = { { 0, 0 },
+       static const u8 timings[][2]= {
+                                   { 0, 0 },
                                    { 0, 0 },
                                    { 1, 0 },
                                    { 2, 1 },
@@ -119,7 +120,6 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        pci_read_config_word(dev, 0x4a, &reg4a);
 
        switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
                case XFER_UDMA_4:       u_speed = 4 << (drive->dn * 4); break;
                case XFER_UDMA_3:       u_speed = 3 << (drive->dn * 4); break;
                case XFER_UDMA_2:       u_speed = 2 << (drive->dn * 4); break;
@@ -128,7 +128,6 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
                case XFER_MW_DMA_2:
                case XFER_MW_DMA_1:
                case XFER_SW_DMA_2:     break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
                case XFER_PIO_4:
                case XFER_PIO_3:
                case XFER_PIO_2:
@@ -156,7 +155,6 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        return (ide_config_drive_speed(drive, speed));
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
 static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
 {
        u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
@@ -194,7 +192,6 @@ fast_ata_pio:
        /* IORDY not supported */
        return 0;
 }
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
 {
@@ -222,7 +219,6 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
        hwif->mwdma_mask = 0x07;
        hwif->swdma_mask = 0x07;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA 
        if (!(hwif->udma_four))
                /* bit[0(1)]: 0:80, 1:40 */
                hwif->udma_four = (reg47 & mask) ? 0 : 1;
@@ -232,7 +228,6 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
                hwif->autodma = 1;
        hwif->drives[0].autodma = hwif->autodma;
        hwif->drives[1].autodma = hwif->autodma;
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
 }
 
 static ide_pci_device_t slc90e66_chipset __devinitdata = {
@@ -250,7 +245,7 @@ static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_dev
 }
 
 static struct pci_device_id slc90e66_pci_tbl[] = {
-       { PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
index ffca8b63ee79af28a1363df86c359fbcde1e12ef..e8ef3455ec356e4c9bf835f42532cb62cf57bea9 100644 (file)
@@ -420,107 +420,6 @@ static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
 
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
-/*
- * Below is the code for blinking the laptop LED along with hard
- * disk activity.
- */
-
-#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
-
-/* Set to 50ms minimum led-on time (also used to limit frequency
- * of requests sent to the PMU
- */
-#define PMU_HD_BLINK_TIME      (HZ/50)
-
-static struct adb_request pmu_blink_on, pmu_blink_off;
-static spinlock_t pmu_blink_lock;
-static unsigned long pmu_blink_stoptime;
-static int pmu_blink_ledstate;
-static struct timer_list pmu_blink_timer;
-static int pmu_ide_blink_enabled;
-
-
-static void
-pmu_hd_blink_timeout(unsigned long data)
-{
-       unsigned long flags;
-       
-       spin_lock_irqsave(&pmu_blink_lock, flags);
-
-       /* We may have been triggered again in a racy way, check
-        * that we really want to switch it off
-        */
-       if (time_after(pmu_blink_stoptime, jiffies))
-               goto done;
-
-       /* Previous req. not complete, try 100ms more */
-       if (pmu_blink_off.complete == 0)
-               mod_timer(&pmu_blink_timer, jiffies + PMU_HD_BLINK_TIME);
-       else if (pmu_blink_ledstate) {
-               pmu_request(&pmu_blink_off, NULL, 4, 0xee, 4, 0, 0);
-               pmu_blink_ledstate = 0;
-       }
-done:
-       spin_unlock_irqrestore(&pmu_blink_lock, flags);
-}
-
-static void
-pmu_hd_kick_blink(void *data, int rw)
-{
-       unsigned long flags;
-       
-       pmu_blink_stoptime = jiffies + PMU_HD_BLINK_TIME;
-       wmb();
-       mod_timer(&pmu_blink_timer, pmu_blink_stoptime);
-       /* Fast path when LED is already ON */
-       if (pmu_blink_ledstate == 1)
-               return;
-       spin_lock_irqsave(&pmu_blink_lock, flags);
-       if (pmu_blink_on.complete && !pmu_blink_ledstate) {
-               pmu_request(&pmu_blink_on, NULL, 4, 0xee, 4, 0, 1);
-               pmu_blink_ledstate = 1;
-       }
-       spin_unlock_irqrestore(&pmu_blink_lock, flags);
-}
-
-static int
-pmu_hd_blink_init(void)
-{
-       struct device_node *dt;
-       const char *model;
-
-       /* Currently, I only enable this feature on KeyLargo based laptops,
-        * older laptops may support it (at least heathrow/paddington) but
-        * I don't feel like loading those venerable old machines with so
-        * much additional interrupt & PMU activity...
-        */
-       if (pmu_get_model() != PMU_KEYLARGO_BASED)
-               return 0;
-       
-       dt = of_find_node_by_path("/");
-       if (dt == NULL)
-               return 0;
-       model = (const char *)get_property(dt, "model", NULL);
-       if (model == NULL)
-               return 0;
-       if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
-           strncmp(model, "iBook", strlen("iBook")) != 0) {
-               of_node_put(dt);
-               return 0;
-       }
-       of_node_put(dt);
-
-       pmu_blink_on.complete = 1;
-       pmu_blink_off.complete = 1;
-       spin_lock_init(&pmu_blink_lock);
-       init_timer(&pmu_blink_timer);
-       pmu_blink_timer.function = pmu_hd_blink_timeout;
-
-       return 1;
-}
-
-#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */
-
 /*
  * N.B. this can't be an initfunc, because the media-bay task can
  * call ide_[un]register at any time.
@@ -1192,23 +1091,6 @@ pmac_ide_do_suspend(ide_hwif_t *hwif)
        pmif->timings[0] = 0;
        pmif->timings[1] = 0;
        
-#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
-       /* Note: This code will be called for every hwif, thus we'll
-        * try several time to stop the LED blinker timer,  but that
-        * should be harmless
-        */
-       if (pmu_ide_blink_enabled) {
-               unsigned long flags;
-
-               /* Make sure we don't hit the PMU blink */
-               spin_lock_irqsave(&pmu_blink_lock, flags);
-               if (pmu_blink_ledstate)
-                       del_timer(&pmu_blink_timer);
-               pmu_blink_ledstate = 0;
-               spin_unlock_irqrestore(&pmu_blink_lock, flags);
-       }
-#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */
-
        disable_irq(pmif->irq);
 
        /* The media bay will handle itself just fine */
@@ -1376,13 +1258,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
                hwif->selectproc = pmac_ide_selectproc;
        hwif->speedproc = pmac_ide_tune_chipset;
 
-#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
-       pmu_ide_blink_enabled = pmu_hd_blink_init();
-
-       if (pmu_ide_blink_enabled)
-               hwif->led_act = pmu_hd_kick_blink;
-#endif
-
        printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n",
               hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
               pmif->mediabay ? " (mediabay)" : "", hwif->irq);
index 3d278412e1ca07f46b9e69887864d1d076c91a26..800c8d5184302b0195f5ab1f34783d718523e192 100644 (file)
@@ -590,11 +590,11 @@ static void ohci_initialize(struct ti_ohci *ohci)
        buf = reg_read(ohci, OHCI1394_Version);
        sprintf (irq_buf, "%d", ohci->dev->irq);
        PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%s]  "
-             "MMIO=[%lx-%lx]  Max Packet=[%d]  IR/IT contexts=[%d/%d]",
+             "MMIO=[%llx-%llx]  Max Packet=[%d]  IR/IT contexts=[%d/%d]",
              ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
              ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), irq_buf,
-             pci_resource_start(ohci->dev, 0),
-             pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
+             (unsigned long long)pci_resource_start(ohci->dev, 0),
+             (unsigned long long)pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
              ohci->max_packet_size,
              ohci->nb_iso_rcv_ctx, ohci->nb_iso_xmit_ctx);
 
@@ -3217,7 +3217,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
 {
        struct hpsb_host *host;
        struct ti_ohci *ohci;   /* shortcut to currently handled device */
-       unsigned long ohci_base;
+       resource_size_t ohci_base;
 
         if (pci_enable_device(dev))
                FAIL(-ENXIO, "Failed to enable OHCI hardware");
@@ -3270,15 +3270,16 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
         * clearly says it's 2kb, so this shouldn't be a problem. */
        ohci_base = pci_resource_start(dev, 0);
        if (pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE)
-               PRINT(KERN_WARNING, "PCI resource length of %lx too small!",
-                     pci_resource_len(dev, 0));
+               PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
+                     (unsigned long long)pci_resource_len(dev, 0));
 
        /* Seems PCMCIA handles this internally. Not sure why. Seems
         * pretty bogus to force a driver to special case this.  */
 #ifndef PCMCIA
        if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME))
-               FAIL(-ENOMEM, "MMIO resource (0x%lx - 0x%lx) unavailable",
-                    ohci_base, ohci_base + OHCI1394_REGISTER_SIZE);
+               FAIL(-ENOMEM, "MMIO resource (0x%llx - 0x%llx) unavailable",
+                       (unsigned long long)ohci_base,
+                       (unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
 #endif
        ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
 
index dddcdae736ac89151d659a65e8521e98523890fb..e4b897fa569a5e945841fee575e1db1706f4ecd4 100644 (file)
@@ -460,10 +460,10 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
        for (j = 0; j < 6; j++) {
                if (!pdev->resource[j].start)
                        continue;
-               ipath_cdbg(VERBOSE, "BAR %d start %lx, end %lx, len %lx\n",
-                          j, pdev->resource[j].start,
-                          pdev->resource[j].end,
-                          pci_resource_len(pdev, j));
+               ipath_cdbg(VERBOSE, "BAR %d start %llx, end %llx, len %llx\n",
+                          j, (unsigned long long)pdev->resource[j].start,
+                          (unsigned long long)pdev->resource[j].end,
+                          (unsigned long long)pci_resource_len(pdev, j));
        }
 
        if (!addr) {
index 9b9ff7bff357a2ea8a4d9ab8d6747eea373ade95..465fd220569c651a1cb7499daa1f970b5241811a 100644 (file)
@@ -172,8 +172,9 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim
 
        if (dev_lim->uar_size > pci_resource_len(mdev->pdev, 2)) {
                mthca_err(mdev, "HCA reported UAR size of 0x%x bigger than "
-                         "PCI resource 2 size of 0x%lx, aborting.\n",
-                         dev_lim->uar_size, pci_resource_len(mdev->pdev, 2));
+                         "PCI resource 2 size of 0x%llx, aborting.\n",
+                         dev_lim->uar_size,
+                         (unsigned long long)pci_resource_len(mdev->pdev, 2));
                return -ENODEV;
        }
 
index de2e7546b491a8878da0677fc40694ec4ba99b3e..a90486f5e49127bf3bbae494d8502d86835f412c 100644 (file)
@@ -998,12 +998,13 @@ void input_unregister_device(struct input_dev *dev)
        sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group);
        sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
        sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
-       class_device_unregister(&dev->cdev);
 
        mutex_lock(&dev->mutex);
        dev->name = dev->phys = dev->uniq = NULL;
        mutex_unlock(&dev->mutex);
 
+       class_device_unregister(&dev->cdev);
+
        input_wakeup_procfs_readers();
 }
 EXPORT_SYMBOL(input_unregister_device);
index 6f31f054d1bb9b144f5edd05c925dbac236795b9..5080e15c6d30c6dca5a1f40fc28c419843cbdf3b 100644 (file)
@@ -584,7 +584,7 @@ static struct db9 __init *db9_probe(int parport, int mode)
                goto err_out;
        }
 
-       if (db9_mode[mode].bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) {
+       if (db9_mode->bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) {
                printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
                err = -EINVAL;
                goto err_put_pp;
index ffde8f86e0fb0277435b2b81355b6a3e92e8ca1d..ce1f10e8984b064beede5a3ea934ecd4894e6ab2 100644 (file)
@@ -459,7 +459,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
                        }
 
                        input_regs(dev, regs);
-                       input_report_key(dev, keycode, value);
+                       input_event(dev, EV_KEY, keycode, value);
                        input_sync(dev);
 
                        if (value && add_release_event) {
index e4e5be111c960b67834e2742a9475bbd73b2d42f..ccf0faeee5c18390ea7ee3f84eb4c1617b00db62 100644 (file)
@@ -285,6 +285,15 @@ static struct key_entry keymap_fujitsu_n3510[] = {
        { KE_END, 0 }
 };
 
+static struct key_entry keymap_wistron_ms2111[] = {
+       { KE_KEY,  0x11, KEY_PROG1 },
+       { KE_KEY,  0x12, KEY_PROG2 },
+       { KE_KEY,  0x13, KEY_PROG3 },
+       { KE_KEY,  0x31, KEY_MAIL },
+       { KE_KEY,  0x36, KEY_WWW },
+       { KE_END,  0 }
+};
+
 static struct key_entry keymap_wistron_ms2141[] = {
        { KE_KEY,  0x11, KEY_PROG1 },
        { KE_KEY,  0x12, KEY_PROG2 },
@@ -326,6 +335,7 @@ static struct key_entry keymap_aopen_1559as[] = {
        { KE_WIFI, 0x30, 0 },
        { KE_KEY,  0x31, KEY_MAIL },
        { KE_KEY,  0x36, KEY_WWW },
+       { KE_END,  0 },
 };
 
 /*
@@ -388,6 +398,15 @@ static struct dmi_system_id dmi_ids[] = {
                },
                .driver_data = keymap_aopen_1559as
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Medion MD 9783",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"),
+               },
+               .driver_data = keymap_wistron_ms2111
+       },
        { NULL, }
 };
 
index 096b6a0b5ccad6598702233350322d71f28860a6..1ac739ef2ffa53a41053b5bd02218f9073c33281 100644 (file)
@@ -189,7 +189,7 @@ static int __devinit ct82c710_probe(struct platform_device *dev)
        strlcpy(ct82c710_port->name, "C&T 82c710 mouse port",
                sizeof(ct82c710_port->name));
        snprintf(ct82c710_port->phys, sizeof(ct82c710_port->phys),
-                "isa%04lx/serio0", CT82C710_DATA);
+                "isa%16llx/serio0", (unsigned long long)CT82C710_DATA);
 
        serio_register_port(ct82c710_port);
 
@@ -241,8 +241,8 @@ static int __init ct82c710_init(void)
 
        serio_register_port(ct82c710_port);
 
-       printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n",
-               CT82C710_DATA, CT82C710_IRQ);
+       printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
+               (unsigned long long)CT82C710_DATA, CT82C710_IRQ);
 
        return 0;
 
index 5a2703b536dc0948bcb8c1b530c6cbff80eb4482..71a8eea816cb1466f698288e36943d45c4db41fb 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 #include <linux/major.h>
 #include <linux/device.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
index 2e541fa020241c468d95dff4f38047cf344f929b..a518ec531021955eed502742a5cec7d007f88bd8 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/moduleparam.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/isdn/capiutil.h>
 #include <linux/isdn/capicmd.h>
 #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
@@ -1337,7 +1336,6 @@ static int capinc_tty_init(void)
 
        drv->owner = THIS_MODULE;
        drv->driver_name = "capi_nc";
-       drv->devfs_name = "capi/";
        drv->name = "capi";
        drv->major = capi_ttymajor;
        drv->minor_start = 0;
@@ -1516,8 +1514,6 @@ static int __init capi_init(void)
        }
 
        class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
-       devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR,
-                       "isdn/capi20");
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
        if (capinc_tty_init() < 0) {
@@ -1552,7 +1548,6 @@ static void __exit capi_exit(void)
        class_device_destroy(capi_class, MKDEV(capi_major, 0));
        class_destroy(capi_class);
        unregister_chrdev(capi_major, "capi20");
-       devfs_remove("isdn/capi20");
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
        capinc_tty_exit();
index 8a45715dd4c10393e6ea9314df12c2abee67ccf4..3845defd49010b840f781740ddbc7d5290e15f5d 100644 (file)
@@ -41,7 +41,6 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode");
 #define GIGASET_MINORS     1
 #define GIGASET_MINOR      16
 #define GIGASET_MODULENAME "bas_gigaset"
-#define GIGASET_DEVFSNAME  "gig/bas/"
 #define GIGASET_DEVNAME    "ttyGB"
 
 /* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */
@@ -2349,8 +2348,7 @@ static int __init bas_gigaset_init(void)
        /* allocate memory for our driver state and intialize it */
        if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
                                       GIGASET_MODULENAME, GIGASET_DEVNAME,
-                                      GIGASET_DEVFSNAME, &gigops,
-                                      THIS_MODULE)) == NULL)
+                                      &gigops, THIS_MODULE)) == NULL)
                goto error;
 
        /* allocate memory for our device state and intialize it */
index acb7e2656780274cd32fc8f4e170f234c3357bc4..aca165d43aa050952dbaaac63e34241cbfd10dd7 100644 (file)
@@ -981,7 +981,7 @@ exit:
 EXPORT_SYMBOL_GPL(gigaset_stop);
 
 static LIST_HEAD(drivers);
-static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(driver_lock);
 
 struct cardstate *gigaset_get_cs_by_id(int id)
 {
@@ -1092,14 +1092,12 @@ EXPORT_SYMBOL_GPL(gigaset_freedriver);
  *     minors          Number of minors this driver can handle
  *     procname        Name of the driver
  *     devname         Name of the device files (prefix without minor number)
- *     devfsname       Devfs name of the device files without %d
  * return value:
  *     Pointer to the gigaset_driver structure on success, NULL on failure.
  */
 struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
                                          const char *procname,
                                          const char *devname,
-                                         const char *devfsname,
                                          const struct gigaset_ops *ops,
                                          struct module *owner)
 {
@@ -1139,7 +1137,7 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
                drv->cs[i].minor_index = i;
        }
 
-       gigaset_if_initdriver(drv, procname, devname, devfsname);
+       gigaset_if_initdriver(drv, procname, devname);
 
        spin_lock_irqsave(&driver_lock, flags);
        list_add(&drv->list, &drivers);
index 8d63d822104fb53bad713ede2175016f800dba4f..1ca3bfdef51d0c43f0cdd839028cf477856589d1 100644 (file)
@@ -769,7 +769,6 @@ void gigaset_block_channels(struct cardstate *cs);
 struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
                                          const char *procname,
                                          const char *devname,
-                                         const char *devfsname,
                                          const struct gigaset_ops *ops,
                                          struct module *owner);
 
@@ -892,7 +891,7 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
 
 /* initialize interface */
 void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
-                          const char *devname, const char *devfsname);
+                          const char *devname);
 /* release interface */
 void gigaset_if_freedriver(struct gigaset_driver *drv);
 /* add minor */
index 74fd234956c8949ac2042161b9254456c87b0dda..bd2e4267528e58aadbcb4f770f75b4cccbc72ba0 100644 (file)
@@ -673,10 +673,9 @@ EXPORT_SYMBOL_GPL(gigaset_if_receive);
  *     drv             Driver
  *     procname        Name of the driver (e.g. for /proc/tty/drivers)
  *     devname         Name of the device files (prefix without minor number)
- *     devfsname       Devfs name of the device files without %d
  */
 void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
-                          const char *devname, const char *devfsname)
+                          const char *devname)
 {
        unsigned minors = drv->minors;
        int ret;
@@ -692,7 +691,7 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
        tty->major =            GIG_MAJOR,
        tty->type =             TTY_DRIVER_TYPE_SERIAL,
        tty->subtype =          SERIAL_TYPE_NORMAL,
-       tty->flags =            TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+       tty->flags =            TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 
        tty->driver_name =      procname;
        tty->name =             devname;
@@ -700,7 +699,6 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
        tty->num =              drv->minors;
 
        tty->owner =            THIS_MODULE;
-       tty->devfs_name =       devfsname;
 
        tty->init_termios          = tty_std_termios; //FIXME
        tty->init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //FIXME
index d86ab68114b0c7848126661c2009816658093c9d..6e05d9d4a51ad13ad0acd55a4b9b9c6a26b3eaa9 100644 (file)
@@ -41,7 +41,6 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode");
 #define GIGASET_MINORS     1
 #define GIGASET_MINOR      8
 #define GIGASET_MODULENAME "usb_gigaset"
-#define GIGASET_DEVFSNAME  "gig/usb/"
 #define GIGASET_DEVNAME    "ttyGU"
 
 #define IF_WRITEBUF 2000 //FIXME  // WAKEUP_CHARS: 256
@@ -896,8 +895,7 @@ static int __init usb_gigaset_init(void)
        /* allocate memory for our driver state and intialize it */
        if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
                                       GIGASET_MODULENAME, GIGASET_DEVNAME,
-                                      GIGASET_DEVFSNAME, &ops,
-                                      THIS_MODULE)) == NULL)
+                                      &ops, THIS_MODULE)) == NULL)
                goto error;
 
        /* allocate memory for our device state and intialize it */
index 9746cc5ffff8d0d7c73dc987372d33f952eb3156..ad5025155b4e9bf7999c84e92ffa76ec39213b95 100644 (file)
@@ -82,7 +82,7 @@ static int b1pcmcia_add_card(unsigned int port, unsigned irq,
        card->irq = irq;
        card->cardtype = cardtype;
 
-       retval = request_irq(card->irq, b1_interrupt, 0, card->name, card);
+       retval = request_irq(card->irq, b1_interrupt, SA_SHIRQ, card->name, card);
        if (retval) {
                printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n",
                       card->irq);
index 6146f7633be5d421b9c113836c22654bd8cbb1b3..b163c5909182d40286c0b01ce41a18448efd40a2 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <linux/poll.h>
-#include <linux/devfs_fs_kernel.h>
 #include <asm/uaccess.h>
 
 #include "platform.h"
@@ -178,7 +177,6 @@ static struct file_operations divas_maint_fops = {
 
 static void divas_maint_unregister_chrdev(void)
 {
-       devfs_remove(DEVNAME);
        unregister_chrdev(major, DEVNAME);
 }
 
@@ -190,7 +188,6 @@ static int DIVA_INIT_FUNCTION divas_maint_register_chrdev(void)
                       DRIVERLNAME);
                return (0);
        }
-       devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
 
        return (1);
 }
index df715b47e2b43f64239821353ab4f9b22c3de4fb..6e7d89a31c1d668a3c2f4b02a28a6542c06b38ae 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
 #include <linux/skbuff.h>
-#include <linux/devfs_fs_kernel.h>
 #include <asm/uaccess.h>
 
 #include "platform.h"
@@ -145,7 +144,6 @@ static struct file_operations divas_idi_fops = {
 
 static void divas_idi_unregister_chrdev(void)
 {
-       devfs_remove(DEVNAME);
        unregister_chrdev(major, DEVNAME);
 }
 
@@ -157,7 +155,6 @@ static int DIVA_INIT_FUNCTION divas_idi_register_chrdev(void)
                       DRIVERLNAME);
                return (0);
        }
-       devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
 
        return (1);
 }
index c9b26e86d183090555540d582eca4631c03d05d8..9dee6a39104c617774454f4da58a968f6a5b57b0 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/devfs_fs_kernel.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/ioport.h>
@@ -678,7 +677,6 @@ static struct file_operations divas_fops = {
 
 static void divas_unregister_chrdev(void)
 {
-       devfs_remove(DEVNAME);
        unregister_chrdev(major, DEVNAME);
 }
 
@@ -690,7 +688,6 @@ static int DIVA_INIT_FUNCTION divas_register_chrdev(void)
                       DRIVERLNAME);
                return (0);
        }
-       devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
 
        return (1);
 }
index 91d25acb5ede07f39d8859204e5b6daa9f150315..3622720f05053a01cb37161ab27b2ce9a2fb6f0c 100644 (file)
@@ -1688,7 +1688,7 @@ setup_hfcpci(struct IsdnCard *card)
                                printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
                                return (0);
                        }
-                       cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->resource[ 1].start;
+                       cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
                        printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
                } else {
                        printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
index 9bb18f3f78298f25dcea5302e5b8278e75956d6b..f9c14a2970bc1a502692edaf19b17a88ffb320a3 100644 (file)
@@ -164,7 +164,7 @@ static int sedlbauer_probe(struct pcmcia_device *link)
     link->priv = local;
 
     /* Interrupt setup */
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
     link->irq.Handler = NULL;
 
index a3eaf4d6570733d3b714425d967ff7e018fb495f..090abd16b4bcb93317109ebc2977538fc447b4c8 100644 (file)
@@ -369,6 +369,7 @@ setup_teles3(struct IsdnCard *card)
                               cs->hw.teles3.hscx[1] + 96);
                        return (0);
                }
+               cs->irq_flags |= SA_SHIRQ; /* cardbus can share */
        } else {
                if (cs->hw.teles3.cfg_reg) {
                        if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
index e2bb4fd8e25e7602e9c69fd0151edb739a119daa..e82ab2251b825089b9f0a28ad68b007c6dbfd0f9 100644 (file)
@@ -311,8 +311,9 @@ setup_telespci(struct IsdnCard *card)
                }
                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);
+               printk(KERN_INFO "Found: Zoran, base-address: 0x%llx, irq: 0x%x\n",
+                       (unsigned long long)pci_resource_start(dev_tel, 0),
+                       dev_tel->irq);
        } else {
                printk(KERN_WARNING "TelesPCI: No PCI card found\n");
                return(0);
index b26e509ec7593a89ba358db502418dce516b3f61..eb21063e6f63fb7939363bf1cdf527d5a38f151a 100644 (file)
@@ -340,6 +340,16 @@ isdn_command(isdn_ctrl *cmd)
                printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
                return(1);
        }
+       if (!dev->drv[cmd->driver]) {
+               printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d] NULL\n",
+                       cmd->command, cmd->driver);
+               return(1);
+       }
+       if (!dev->drv[cmd->driver]->interface) {
+               printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d]->interface NULL\n",
+                       cmd->command, cmd->driver);
+               return(1);
+       }
        if (cmd->command == ISDN_CMD_SETL2) {
                int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
                unsigned long l2prot = (cmd->arg >> 8) & 255;
@@ -1903,6 +1913,11 @@ isdn_free_channel(int di, int ch, int usage)
 {
        int i;
 
+       if ((di < 0) || (ch < 0)) {
+               printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n",
+                       __FUNCTION__, di, ch);
+               return;
+       }
        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
                if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) &&
                    (dev->drvmap[i] == di) &&
@@ -1918,7 +1933,8 @@ isdn_free_channel(int di, int ch, int usage)
                        dev->v110[i] = NULL;
 // 20.10.99 JIM, try to reinitialize v110 !
                        isdn_info_update();
-                       skb_queue_purge(&dev->drv[di]->rpqueue[ch]);
+                       if (dev->drv[di])
+                               skb_queue_purge(&dev->drv[di]->rpqueue[ch]);
                }
 }
 
index 2ac90242d263714b7d6108a9005982ef660c02d7..0a53a990c100a2662102cab27823c1b6a7e0b5a0 100644 (file)
@@ -82,7 +82,7 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
                                                int l = skb->len;
                                                unsigned char *dp = skb->data;
                                                while (--l) {
-                                                       if (*skb->data == DLE)
+                                                       if (*dp == DLE)
                                                                tty_insert_flip_char(tty, DLE, 0);
                                                        tty_insert_flip_char(tty, *dp++, 0);
                                                }
@@ -1890,14 +1890,13 @@ isdn_tty_modem_init(void)
        if (!m->tty_modem)
                return -ENOMEM;
        m->tty_modem->name = "ttyI";
-       m->tty_modem->devfs_name = "isdn/ttyI";
        m->tty_modem->major = ISDN_TTY_MAJOR;
        m->tty_modem->minor_start = 0;
        m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL;
        m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
        m->tty_modem->init_termios = tty_std_termios;
        m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        m->tty_modem->driver_name = "isdn_tty";
        tty_set_operations(m->tty_modem, &modem_ops);
        retval = tty_register_driver(m->tty_modem);
index 743ac4077f35b24b17af0b08fc5a23dce9b0733f..8b3efc243161a201fd8029d5d43900371c48b2b5 100644 (file)
@@ -208,7 +208,7 @@ static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb
  */
 static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
 {
-       struct sk_buff * skb = dev_alloc_skb(1);
+       struct sk_buff * skb;
        enum wan_states *state_p 
          = &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
        IX25DEBUG( "isdn_x25iface_connect_ind %s \n"
@@ -220,6 +220,8 @@ static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
                return -1;
        }
        *state_p = WAN_CONNECTED;
+
+       skb = dev_alloc_skb(1);
        if( skb ){
                *( skb_put(skb, 1) ) = 0x01;
                skb->protocol = x25_type_trans(skb, cprot->net_dev);
index fe6541326c717fb996cb591aebb5a1bbc2107569..9b015f9af351e49526eb52ec0f0c09b4acb21e56 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/leds.h>
 #include "leds.h"
 
-rwlock_t leds_list_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(leds_list_lock);
 LIST_HEAD(leds_list);
 
 EXPORT_SYMBOL_GPL(leds_list);
index 5e2cd8be1191b99c44f3cb573d6bce3487b0155c..1b1ce6523960cb1676f342a718adf2e0962c42a6 100644 (file)
@@ -26,7 +26,7 @@
 /*
  * Nests outside led_cdev->trigger_lock
  */
-static rwlock_t triggers_list_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(triggers_list_lock);
 static LIST_HEAD(trigger_list);
 
 ssize_t led_trigger_store(struct class_device *dev, const char *buf,
index 37cd6ee4586b35b6110a5d948a5dd01d1bbd6031..54f3f6b94efc1e4ac9a2a3bfdff4a70dbf6b2863 100644 (file)
@@ -78,6 +78,18 @@ config ADB_PMU
          this device; you should do so if your machine is one of those
          mentioned above.
 
+config ADB_PMU_LED
+       bool "Support for the Power/iBook front LED"
+       depends on ADB_PMU
+       select NEW_LEDS
+       select LEDS_CLASS
+       help
+         Support the front LED on Power/iBooks as a generic LED that can
+         be triggered by any of the supported triggers. To get the
+         behaviour of the old CONFIG_BLK_DEV_IDE_PMAC_BLINK, select this
+         and the ide-disk LED trigger and configure appropriately through
+         sysfs.
+
 config PMAC_SMU
        bool "Support for SMU  based PowerMacs"
        depends on PPC_PMAC64
index 45a268f8047ed83fd39503cc116e0e6ea9b8675b..b53d45f87b0bee7a74834cab9b2897f7d8eaa0f9 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_ADBHID)    += adbhid.o
 obj-$(CONFIG_ANSLCD)           += ans-lcd.o
 
 obj-$(CONFIG_ADB_PMU)          += via-pmu.o via-pmu-event.o
+obj-$(CONFIG_ADB_PMU_LED)      += via-pmu-led.o
 obj-$(CONFIG_PMAC_BACKLIGHT)   += via-pmu-backlight.o
 obj-$(CONFIG_ADB_CUDA)         += via-cuda.o
 obj-$(CONFIG_PMAC_APM_EMU)     += apm_emu.o
index 259fd8973ce94c076064a2323a38b467d325d9c4..9f1a049dc226a4d2a3086130ab0164f7889edbd2 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/device.h>
-#include <linux/devfs_fs_kernel.h>
 
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
@@ -904,8 +903,6 @@ adbdev_init(void)
                return;
        }
 
-       devfs_mk_cdev(MKDEV(ADB_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "adb");
-
        adb_dev_class = class_create(THIS_MODULE, "adb");
        if (IS_ERR(adb_dev_class))
                return;
index 431bd37225a13a05be8891b44de545e88b5802c1..c687ac703941f514af7c352ab456e72be2fc18e2 100644 (file)
@@ -428,10 +428,10 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
 
        /* MacIO itself has a different reg, we use it's PCI base */
        if (np == chip->of_node) {
-               sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s",
+               sprintf(dev->ofdev.dev.bus_id, "%1d.%016llx:%.*s",
                        chip->lbus.index,
 #ifdef CONFIG_PCI
-                       pci_resource_start(chip->lbus.pdev, 0),
+                       (unsigned long long)pci_resource_start(chip->lbus.pdev, 0),
 #else
                        0, /* NuBus may want to do something better here */
 #endif
diff --git a/drivers/macintosh/via-pmu-led.c b/drivers/macintosh/via-pmu-led.c
new file mode 100644 (file)
index 0000000..af8375e
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * via-pmu LED class device
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.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, 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/leds.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/prom.h>
+
+static spinlock_t pmu_blink_lock;
+static struct adb_request pmu_blink_req;
+/* -1: no change, 0: request off, 1: request on */
+static int requested_change;
+static int sleeping;
+
+static void pmu_req_done(struct adb_request * req)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmu_blink_lock, flags);
+       /* if someone requested a change in the meantime
+        * (we only see the last one which is fine)
+        * then apply it now */
+       if (requested_change != -1 && !sleeping)
+               pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
+       /* reset requested change */
+       requested_change = -1;
+       spin_unlock_irqrestore(&pmu_blink_lock, flags);
+}
+
+static void pmu_led_set(struct led_classdev *led_cdev,
+                       enum led_brightness brightness)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmu_blink_lock, flags);
+       switch (brightness) {
+       case LED_OFF:
+               requested_change = 0;
+               break;
+       case LED_FULL:
+               requested_change = 1;
+               break;
+       default:
+               goto out;
+               break;
+       }
+       /* if request isn't done, then don't do anything */
+       if (pmu_blink_req.complete && !sleeping)
+               pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
+ out:
+       spin_unlock_irqrestore(&pmu_blink_lock, flags);
+}
+
+static struct led_classdev pmu_led = {
+       .name = "pmu-front-led",
+#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
+       .default_trigger = "ide-disk",
+#endif
+       .brightness_set = pmu_led_set,
+};
+
+#ifdef CONFIG_PM
+static int pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmu_blink_lock, flags);
+
+       switch (when) {
+       case PBOOK_SLEEP_REQUEST:
+               sleeping = 1;
+               break;
+       case PBOOK_WAKE:
+               sleeping = 0;
+               break;
+       default:
+               /* do nothing */
+               break;
+       }
+       spin_unlock_irqrestore(&pmu_blink_lock, flags);
+
+       return PBOOK_SLEEP_OK;
+}
+
+static struct pmu_sleep_notifier via_pmu_led_sleep_notif = {
+       .notifier_call = pmu_led_sleep_call,
+};
+#endif
+
+static int __init via_pmu_led_init(void)
+{
+       struct device_node *dt;
+       const char *model;
+
+       /* only do this on keylargo based models */
+       if (pmu_get_model() != PMU_KEYLARGO_BASED)
+               return -ENODEV;
+
+       dt = of_find_node_by_path("/");
+       if (dt == NULL)
+               return -ENODEV;
+       model = (const char *)get_property(dt, "model", NULL);
+       if (model == NULL)
+               return -ENODEV;
+       if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
+           strncmp(model, "iBook", strlen("iBook")) != 0) {
+               of_node_put(dt);
+               /* ignore */
+               return -ENODEV;
+       }
+       of_node_put(dt);
+
+       spin_lock_init(&pmu_blink_lock);
+       /* no outstanding req */
+       pmu_blink_req.complete = 1;
+       pmu_blink_req.done = pmu_req_done;
+#ifdef CONFIG_PM
+       pmu_register_sleep_notifier(&via_pmu_led_sleep_notif);
+#endif
+       return led_classdev_register(NULL, &pmu_led);
+}
+
+late_initcall(via_pmu_led_init);
index 3edb3477f987d4199c32d94e96d03e2c40e3ef1f..d13bb15a8a02981f69706048d32bfc64b83b73c1 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/dm-ioctl.h>
 #include <linux/hdreg.h>
 
@@ -68,14 +67,12 @@ static int dm_hash_init(void)
 {
        init_buckets(_name_buckets);
        init_buckets(_uuid_buckets);
-       devfs_mk_dir(DM_DIR);
        return 0;
 }
 
 static void dm_hash_exit(void)
 {
        dm_hash_remove_all(0);
-       devfs_remove(DM_DIR);
 }
 
 /*-----------------------------------------------------------------
@@ -171,25 +168,6 @@ static void free_cell(struct hash_cell *hc)
        }
 }
 
-/*
- * devfs stuff.
- */
-static int register_with_devfs(struct hash_cell *hc)
-{
-       struct gendisk *disk = dm_disk(hc->md);
-
-       devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
-                     S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-                     DM_DIR "/%s", hc->name);
-       return 0;
-}
-
-static int unregister_with_devfs(struct hash_cell *hc)
-{
-       devfs_remove(DM_DIR"/%s", hc->name);
-       return 0;
-}
-
 /*
  * The kdev_t and uuid of a device can never change once it is
  * initially inserted.
@@ -226,7 +204,6 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi
                }
                list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
        }
-       register_with_devfs(cell);
        dm_get(md);
        dm_set_mdptr(md, cell);
        up_write(&_hash_lock);
@@ -246,7 +223,6 @@ static void __hash_remove(struct hash_cell *hc)
        /* remove from the dev hash */
        list_del(&hc->uuid_list);
        list_del(&hc->name_list);
-       unregister_with_devfs(hc);
        dm_set_mdptr(hc->md, NULL);
 
        table = dm_get_table(hc->md);
@@ -342,16 +318,11 @@ static int dm_hash_rename(const char *old, const char *new)
        /*
         * rename and move the name cell.
         */
-       unregister_with_devfs(hc);
-
        list_del(&hc->name_list);
        old_name = hc->name;
        hc->name = new_name;
        list_add(&hc->name_list, _name_buckets + hash_str(new_name));
 
-       /* rename the device node in devfs */
-       register_with_devfs(hc);
-
        /*
         * Wake up any dm event waiters.
         */
@@ -1501,7 +1472,6 @@ static struct file_operations _ctl_fops = {
 static struct miscdevice _dm_misc = {
        .minor          = MISC_DYNAMIC_MINOR,
        .name           = DM_NAME,
-       .devfs_name     = "mapper/control",
        .fops           = &_ctl_fops
 };
 
index 3ed2e53b9eb6aa71051e7aafc3ecbbee132b732c..c99bf9f017599a1002a15f608ea356639239dedd 100644 (file)
@@ -167,7 +167,7 @@ static void local_exit(void)
        bioset_free(dm_set);
 
        if (unregister_blkdev(_major, _name) < 0)
-               DMERR("devfs_unregister_blkdev failed");
+               DMERR("unregister_blkdev failed");
 
        _major = 0;
 
index 306268ec99ff11572e975145f3f916ee4144cf63..2ec1b3520a0b7245344610bba7fd1763beb9d25d 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/raid/md.h>
 #include <linux/raid/bitmap.h>
 #include <linux/sysctl.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/buffer_head.h> /* for invalidate_bdev */
 #include <linux/suspend.h>
 #include <linux/poll.h>
@@ -2911,13 +2910,10 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
        }
        disk->major = MAJOR(dev);
        disk->first_minor = unit << shift;
-       if (partitioned) {
+       if (partitioned)
                sprintf(disk->disk_name, "md_d%d", unit);
-               sprintf(disk->devfs_name, "md/d%d", unit);
-       } else {
+       else
                sprintf(disk->disk_name, "md%d", unit);
-               sprintf(disk->devfs_name, "md/%d", unit);
-       }
        disk->fops = &md_fops;
        disk->private_data = mddev;
        disk->queue = mddev->queue;
@@ -5538,8 +5534,6 @@ static void md_geninit(void)
 
 static int __init md_init(void)
 {
-       int minor;
-
        printk(KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d,"
                        " MD_SB_DISKS=%d\n",
                        MD_MAJOR_VERSION, MD_MINOR_VERSION,
@@ -5553,23 +5547,11 @@ static int __init md_init(void)
                unregister_blkdev(MAJOR_NR, "md");
                return -1;
        }
-       devfs_mk_dir("md");
        blk_register_region(MKDEV(MAJOR_NR, 0), MAX_MD_DEVS, THIS_MODULE,
                                md_probe, NULL, NULL);
        blk_register_region(MKDEV(mdp_major, 0), MAX_MD_DEVS<<MdpMinorShift, THIS_MODULE,
                            md_probe, NULL, NULL);
 
-       for (minor=0; minor < MAX_MD_DEVS; ++minor)
-               devfs_mk_bdev(MKDEV(MAJOR_NR, minor),
-                               S_IFBLK|S_IRUSR|S_IWUSR,
-                               "md/%d", minor);
-
-       for (minor=0; minor < MAX_MD_DEVS; ++minor)
-               devfs_mk_bdev(MKDEV(mdp_major, minor<<MdpMinorShift),
-                             S_IFBLK|S_IRUSR|S_IWUSR,
-                             "md/mdp%d", minor);
-
-
        register_reboot_notifier(&md_notifier);
        raid_table_header = register_sysctl_table(raid_root_table, 1);
 
@@ -5625,15 +5607,9 @@ static __exit void md_exit(void)
 {
        mddev_t *mddev;
        struct list_head *tmp;
-       int i;
+
        blk_unregister_region(MKDEV(MAJOR_NR,0), MAX_MD_DEVS);
        blk_unregister_region(MKDEV(mdp_major,0), MAX_MD_DEVS << MdpMinorShift);
-       for (i=0; i < MAX_MD_DEVS; i++)
-               devfs_remove("md/%d", i);
-       for (i=0; i < MAX_MD_DEVS; i++)
-               devfs_remove("md/d%d", i);
-
-       devfs_remove("md");
 
        unregister_blkdev(MAJOR_NR,"md");
        unregister_blkdev(mdp_major, "mdp");
index f920e50ea124dfe9052288f8f526cb314b230249..837ec4eb3d604ce4e01023ccf87d0804ceef7f88 100644 (file)
@@ -2827,7 +2827,6 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
        struct stripe_head *sh;
        int pd_idx;
        int raid_disks = conf->raid_disks;
-       int data_disks = raid_disks - conf->max_degraded;
        sector_t max_sector = mddev->size << 1;
        int sync_blocks;
        int still_degraded = 0;
index 134c2bbbeeb5f75e89921413850a0bffec367ed6..40774feb8953d241566ef2cc79d3e5a11d3fdeb2 100644 (file)
@@ -231,10 +231,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 
        mutex_unlock(&dvbdev_register_lock);
 
-       devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
-                       S_IFCHR | S_IRUSR | S_IWUSR,
-                       "dvb/adapter%d/%s%d", adap->num, dnames[type], id);
-
        class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
                            adap->device, "dvb%d.%s%d", adap->num, dnames[type], id);
 
@@ -252,9 +248,6 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
        if (!dvbdev)
                return;
 
-       devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
-                       dnames[dvbdev->type], dvbdev->id);
-
        class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
                                        dvbdev->type, dvbdev->id)));
 
@@ -302,7 +295,6 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
 
        printk ("DVB: registering new adapter (%s).\n", name);
 
-       devfs_mk_dir("dvb/adapter%d", num);
        adap->num = num;
        adap->name = name;
        adap->module = module;
@@ -319,8 +311,6 @@ EXPORT_SYMBOL(dvb_register_adapter);
 
 int dvb_unregister_adapter(struct dvb_adapter *adap)
 {
-       devfs_remove("dvb/adapter%d", adap->num);
-
        if (mutex_lock_interruptible(&dvbdev_register_lock))
                return -ERESTARTSYS;
        list_del (&adap->list_head);
@@ -410,8 +400,6 @@ static int __init init_dvbdev(void)
                goto error;
        }
 
-       devfs_mk_dir("dvb");
-
        dvb_class = class_create(THIS_MODULE, "dvb");
        if (IS_ERR(dvb_class)) {
                retval = PTR_ERR(dvb_class);
@@ -428,7 +416,6 @@ error:
 
 static void __exit exit_dvbdev(void)
 {
-       devfs_remove("dvb");
        class_destroy(dvb_class);
        cdev_del(&dvb_device_cdev);
        unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
index d7a976d040d72249ab8d5558529d328802356c4e..7a7f75fd168c30f19bf622a349322994914ca336 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/poll.h>
 #include <linux/fs.h>
 #include <linux/list.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
 
 #define DVB_MAJOR 212
index 3e2e12124bae0228bd91a69fee9183129fe2bc32..9c79696da08a60d622aaf347cc5a67609fe74388 100644 (file)
@@ -6,10 +6,6 @@
 #include <linux/netdevice.h>
 #include <linux/i2c.h>
 
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
-#endif
-
 #include <linux/dvb/video.h>
 #include <linux/dvb/audio.h>
 #include <linux/dvb/dmx.h>
index 14559ef6153c4ead4a0468e1411a35ef70c5e5ca..336b2fe1a5f2e13463ba5247bdf41085103ff965 100644 (file)
@@ -126,10 +126,6 @@ struct ttusb {
 
        int revision;
 
-#if 0
-       devfs_handle_t stc_devfs_handle;
-#endif
-
        struct dvb_frontend* fe;
 };
 
@@ -1746,13 +1742,6 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
                return -ENODEV;
        }
 
-#if 0
-       ttusb->stc_devfs_handle =
-           devfs_register(ttusb->adapter->devfs_handle, TTUSB_BUDGET_NAME,
-                          DEVFS_FL_DEFAULT, 0, 192,
-                          S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
-                          | S_IROTH | S_IWOTH, &stc_fops, ttusb);
-#endif
        usb_set_intfdata(intf, (void *) ttusb);
 
        frontend_init(ttusb);
index 87b37b7691dad387cd082b10c030b9c0829947f3..c1b1db65e66821544b541ca37eed4d9fa2491643 100644 (file)
@@ -115,7 +115,6 @@ static struct file_operations rds_fops = {
 static struct miscdevice rds_miscdev = {
        .minor          = MISC_DYNAMIC_MINOR,
        .name           = "radiotext",
-       .devfs_name     = "v4l/rds/radiotext",
        .fops           = &rds_fops,
 };
 
index e4290491fa9e15f4920317c65536f100f180164c..6d532f170ce5c8302b82975c4bb53c8a2dbeef1d 100644 (file)
@@ -445,6 +445,8 @@ endmenu # encoder / decoder chips
 menu "V4L USB devices"
        depends on USB && VIDEO_DEV
 
+source "drivers/media/video/pvrusb2/Kconfig"
+
 source "drivers/media/video/em28xx/Kconfig"
 
 config USB_DSBR
index 6c401b46398a11d8615fadd5641c88d0d6b76fbb..353d61cfac1b2150021762ed5529ae3ad81b089f 100644 (file)
@@ -47,6 +47,7 @@ obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
+obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
 obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
 obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
index 6e08e32346eb9272774c14796e81a0c36da8b7e7..ae14f5f32039cffb00016bc07ab677a340b343a1 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/config.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
index 423e954948beb01153b17aafadaf694100996749..aa3203ae670c94a7333fd6c2ea4561179ab6c676 100644 (file)
@@ -4019,8 +4019,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        if (!request_mem_region(pci_resource_start(dev,0),
                                pci_resource_len(dev,0),
                                btv->c.name)) {
-               printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
-                      btv->c.nr, pci_resource_start(dev,0));
+               printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
+                      btv->c.nr,
+                      (unsigned long long)pci_resource_start(dev,0));
                return -EBUSY;
        }
        pci_set_master(dev);
@@ -4031,8 +4032,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
        printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
               bttv_num,btv->id, btv->revision, pci_name(dev));
-       printk("irq: %d, latency: %d, mmio: 0x%lx\n",
-              btv->c.pci->irq, lat, pci_resource_start(dev,0));
+       printk("irq: %d, latency: %d, mmio: 0x%llx\n",
+              btv->c.pci->irq, lat,
+              (unsigned long long)pci_resource_start(dev,0));
        schedule();
 
        btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
index 01b22eab572574827fc0de12c6e580f8a0c84061..65f00fc08fa961d5671ccfe5a3cf92aa38efb4ab 100644 (file)
@@ -601,7 +601,7 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
 }
 
 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
-                 struct v4l2_ext_controls *ctrls, int cmd)
+                 struct v4l2_ext_controls *ctrls, unsigned int cmd)
 {
        int err = 0;
        int i;
@@ -847,22 +847,22 @@ invalid:
        return "<invalid>";
 }
 
-void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
 {
        int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
 
        /* Stream */
-       printk(KERN_INFO "cx2341x-%d: Stream: %s\n",
-               card_id,
+       printk(KERN_INFO "%s: Stream: %s\n",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
 
        /* Video */
-       printk(KERN_INFO "cx2341x-%d: Video:  %dx%d, %d fps\n",
-               card_id,
+       printk(KERN_INFO "%s: Video:  %dx%d, %d fps\n",
+               prefix,
                p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
                p->is_50hz ? 25 : 30);
-       printk(KERN_INFO "cx2341x-%d: Video:  %s, %s, %s, %d",
-               card_id,
+       printk(KERN_INFO "%s: Video:  %s, %s, %s, %d",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
                cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
                cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
@@ -871,19 +871,19 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
                printk(", Peak %d", p->video_bitrate_peak);
        }
        printk("\n");
-       printk(KERN_INFO "cx2341x-%d: Video:  GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
-               card_id,
+       printk(KERN_INFO "%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+               prefix,
                p->video_gop_size, p->video_b_frames,
                p->video_gop_closure ? "" : "No ",
                p->video_pulldown ? "" : "No ");
        if (p->video_temporal_decimation) {
-               printk(KERN_INFO "cx2341x-%d: Video: Temporal Decimation %d\n",
-                       card_id, p->video_temporal_decimation);
+               printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
+                       prefix, p->video_temporal_decimation);
        }
 
        /* Audio */
-       printk(KERN_INFO "cx2341x-%d: Audio:  %s, %s, %s, %s",
-               card_id,
+       printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
@@ -897,18 +897,18 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
                cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
 
        /* Encoding filters */
-       printk(KERN_INFO "cx2341x-%d: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
-               card_id,
+       printk(KERN_INFO "%s: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
                cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
                cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
                p->video_spatial_filter);
-       printk(KERN_INFO "cx2341x-%d: Temporal Filter: %s, %d\n",
-               card_id,
+       printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
                p->video_temporal_filter);
-       printk(KERN_INFO "cx2341x-%d: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
-               card_id,
+       printk(KERN_INFO "%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
+               prefix,
                cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
                p->video_luma_median_filter_bottom,
                p->video_luma_median_filter_top,
index 2194cbeca33b61b3c1eccf4864cbccbec44e4566..292a5e81eb75fab5ad9a855f3623dae38b80067b 100644 (file)
@@ -712,9 +712,9 @@ static int __devinit snd_cx88_create(struct snd_card *card,
        pci_read_config_byte(pci, PCI_LATENCY_TIMER,  &chip->pci_lat);
 
        dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
-              "latency: %d, mmio: 0x%lx\n", core->name, devno,
+              "latency: %d, mmio: 0x%llx\n", core->name, devno,
               pci_name(pci), chip->pci_rev, pci->irq,
-              chip->pci_lat,pci_resource_start(pci,0));
+              chip->pci_lat,(unsigned long long)pci_resource_start(pci,0));
 
        chip->irq = pci->irq;
        synchronize_irq(chip->irq);
@@ -766,8 +766,8 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
 
        strcpy (card->driver, "CX88x");
        sprintf(card->shortname, "Conexant CX%x", pci->device);
-       sprintf(card->longname, "%s at %#lx",
-               card->shortname, pci_resource_start(pci, 0));
+       sprintf(card->longname, "%s at %#llx",
+               card->shortname,(unsigned long long)pci_resource_start(pci, 0));
        strcpy (card->mixername, "CX88");
 
        dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
index 78df66671ea2f300ba78a07a65e443d7b84690a3..4ff81582ec56ee5f71b17ec2e402c51730ce4698 100644 (file)
@@ -853,6 +853,19 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
                               fh->mpegq.field);
                return 0;
        }
+       case VIDIOC_LOG_STATUS:
+       {
+               char name[32 + 2];
+
+               snprintf(name, sizeof(name), "%s/2", core->name);
+               printk("%s/2: ============  START LOG STATUS  ============\n",
+                      core->name);
+               cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, 0);
+               cx2341x_log_status(&dev->params, name);
+               printk("%s/2: =============  END LOG STATUS  =============\n",
+                      core->name);
+               return 0;
+       }
 
        default:
                return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
index 26f4c0fb8c36cab989a9f2ab7a8269f9e6f6f11c..973d3f39b2d540133c5398abd4e028956dee212b 100644 (file)
@@ -1031,8 +1031,8 @@ static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
                               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));
+       printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+              core->name,(unsigned long long)pci_resource_start(pci,0));
        return -EBUSY;
 }
 
index a9d7795a8e143563ed155c109d474d725671012e..2c12aca1b6a3d69fdf8a2b1f5e91e7cac7856093 100644 (file)
@@ -420,9 +420,9 @@ int cx8802_init_common(struct cx8802_dev *dev)
        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,
+              "latency: %d, mmio: 0x%llx\n", dev->core->name,
               pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
-              dev->pci_lat,pci_resource_start(dev->pci,0));
+              dev->pci_lat,(unsigned long long)pci_resource_start(dev->pci,0));
 
        /* initialize driver struct */
        spin_lock_init(&dev->slock);
index dcda5291b990e979c8490001ea18d7fedc053d6e..8d5cf474b68e817c9729d40ad3f5745092290d9c 100644 (file)
@@ -1847,9 +1847,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
-              "latency: %d, mmio: 0x%lx\n", core->name,
+              "latency: %d, mmio: 0x%llx\n", core->name,
               pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
-              dev->pci_lat,pci_resource_start(pci_dev,0));
+              dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
 
        pci_set_master(pci_dev);
        if (!pci_dma_supported(pci_dev,0xffffffff)) {
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
new file mode 100644 (file)
index 0000000..7e727fe
--- /dev/null
@@ -0,0 +1,62 @@
+config VIDEO_PVRUSB2
+       tristate "Hauppauge WinTV-PVR USB2 support"
+       depends on VIDEO_V4L2 && USB && I2C && EXPERIMENTAL
+       select FW_LOADER
+       select VIDEO_TUNER
+       select VIDEO_TVEEPROM
+       select VIDEO_CX2341X
+       select VIDEO_SAA711X
+       select VIDEO_MSP3400
+       ---help---
+         This is a video4linux driver for Conexant 23416 based
+         usb2 personal video recorder devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called pvrusb2
+
+config VIDEO_PVRUSB2_24XXX
+       bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
+       depends on VIDEO_PVRUSB2 && EXPERIMENTAL
+       select VIDEO_CX25840
+       select VIDEO_WM8775
+       ---help---
+         This option enables inclusion of additional logic to operate
+         newer WinTV-PVR USB2 devices whose model number is of the
+         form "24xxx" (leading prefix of "24" followed by 3 digits).
+         To see if you may need this option, examine the white
+         sticker on the underside of your device.  Enabling this
+         option will not harm support for older devices, however it
+         is a separate option because of the experimental nature of
+         this new feature.
+
+         If you are in doubt, say N.
+
+         Note: This feature is _very_ experimental.  You have been
+         warned.
+
+config VIDEO_PVRUSB2_SYSFS
+       bool "pvrusb2 sysfs support (EXPERIMENTAL)"
+       default y
+       depends on VIDEO_PVRUSB2 && SYSFS && EXPERIMENTAL
+       ---help---
+         This option enables the operation of a sysfs based
+         interface for query and control of the pvrusb2 driver.
+
+         This is not generally needed for v4l applications,
+         although certain applications are optimized to take
+         advantage of this feature.
+
+         If you are in doubt, say Y.
+
+         Note: This feature is experimental and subject to change.
+
+config VIDEO_PVRUSB2_DEBUGIFC
+       bool "pvrusb2 debug interface"
+       depends on VIDEO_PVRUSB2_SYSFS
+       ---help---
+         This option enables the inclusion of a debug interface
+         in the pvrusb2 driver, hosted through sysfs.
+
+         You do not need to select this option unless you plan
+         on debugging the driver or performing a manual firmware
+         extraction.
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
new file mode 100644 (file)
index 0000000..fed603a
--- /dev/null
@@ -0,0 +1,18 @@
+obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
+obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
+
+obj-pvrusb2-24xxx-$(CONFIG_VIDEO_PVRUSB2_24XXX) := \
+                  pvrusb2-cx2584x-v4l.o \
+                  pvrusb2-wm8775.o
+
+pvrusb2-objs   := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
+                  pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
+                  pvrusb2-encoder.o pvrusb2-video-v4l.o \
+                  pvrusb2-eeprom.o pvrusb2-tuner.o pvrusb2-demod.o \
+                  pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
+                  pvrusb2-ctrl.o pvrusb2-std.o \
+                  pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
+                  $(obj-pvrusb2-24xxx-y) \
+                  $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
+
+obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
new file mode 100644 (file)
index 0000000..313d2dc
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-audio.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/msp3400.h>
+#include <media/v4l2-common.h>
+
+struct pvr2_msp3400_handler {
+       struct pvr2_hdw *hdw;
+       struct pvr2_i2c_client *client;
+       struct pvr2_i2c_handler i2c_handler;
+       struct pvr2_audio_stat astat;
+       unsigned long stale_mask;
+};
+
+
+/* This function selects the correct audio input source */
+static void set_stereo(struct pvr2_msp3400_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       struct v4l2_routing route;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
+
+       if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
+               struct v4l2_tuner vt;
+               memset(&vt,0,sizeof(vt));
+               vt.audmode = hdw->audiomode_val;
+               pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt);
+       }
+
+       route.input = MSP_INPUT_DEFAULT;
+       route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+       switch (hdw->input_val) {
+       case PVR2_CVAL_INPUT_TV:
+               break;
+       case PVR2_CVAL_INPUT_RADIO:
+               /* Assume that msp34xx also handle FM decoding, in which case
+                  we're still using the tuner. */
+               /* HV: actually it is more likely to be the SCART2 input if
+                  the ivtv experience is any indication. */
+               route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+                                   MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+               break;
+       case PVR2_CVAL_INPUT_SVIDEO:
+       case PVR2_CVAL_INPUT_COMPOSITE:
+               /* SCART 1 input */
+               route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+                                   MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+               break;
+       }
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+
+static int check_stereo(struct pvr2_msp3400_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return (hdw->input_dirty ||
+               hdw->audiomode_dirty);
+}
+
+
+struct pvr2_msp3400_ops {
+       void (*update)(struct pvr2_msp3400_handler *);
+       int (*check)(struct pvr2_msp3400_handler *);
+};
+
+
+static const struct pvr2_msp3400_ops msp3400_ops[] = {
+       { .update = set_stereo, .check = check_stereo},
+};
+
+
+static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (ctxt->stale_mask & msk) continue;
+               if (msp3400_ops[idx].check(ctxt)) {
+                       ctxt->stale_mask |= msk;
+               }
+       }
+       return ctxt->stale_mask != 0;
+}
+
+
+static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (!(ctxt->stale_mask & msk)) continue;
+               ctxt->stale_mask &= ~msk;
+               msp3400_ops[idx].update(ctxt);
+       }
+}
+
+
+/* This reads back the current signal type */
+static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
+{
+       struct v4l2_tuner vt;
+       int stat;
+
+       memset(&vt,0,sizeof(vt));
+       stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
+       if (stat < 0) return stat;
+
+       ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0;
+       ctxt->hdw->flag_bilingual =
+               (vt.audmode & V4L2_TUNER_MODE_LANG2) != 0;
+       return 0;
+}
+
+
+static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
+{
+       ctxt->client->handler = 0;
+       ctxt->hdw->audio_stat = 0;
+       kfree(ctxt);
+}
+
+
+static unsigned int pvr2_msp3400_describe(struct pvr2_msp3400_handler *ctxt,
+                                         char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-audio v4l2");
+}
+
+
+const static struct pvr2_i2c_handler_functions msp3400_funcs = {
+       .detach = (void (*)(void *))pvr2_msp3400_detach,
+       .check = (int (*)(void *))msp3400_check,
+       .update = (void (*)(void *))msp3400_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_msp3400_describe,
+};
+
+
+int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+       struct pvr2_msp3400_handler *ctxt;
+       if (hdw->audio_stat) return 0;
+       if (cp->handler) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->i2c_handler.func_data = ctxt;
+       ctxt->i2c_handler.func_table = &msp3400_funcs;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       ctxt->astat.ctxt = ctxt;
+       ctxt->astat.status = (int (*)(void *))get_audio_status;
+       ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach;
+       ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/
+                                 sizeof(msp3400_ops[0]))) - 1;
+       cp->handler = &ctxt->i2c_handler;
+       hdw->audio_stat = &ctxt->astat;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.h b/drivers/media/video/pvrusb2/pvrusb2-audio.h
new file mode 100644 (file)
index 0000000..536339b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_AUDIO_H
+#define __PVRUSB2_AUDIO_H
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_msp3400_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+#endif /* __PVRUSB2_AUDIO_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
new file mode 100644 (file)
index 0000000..40dc598
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 "pvrusb2-context.h"
+#include "pvrusb2-io.h"
+#include "pvrusb2-ioread.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-debug.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+
+
+static void pvr2_context_destroy(struct pvr2_context *mp)
+{
+       if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
+       pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
+       flush_workqueue(mp->workqueue);
+       destroy_workqueue(mp->workqueue);
+       kfree(mp);
+}
+
+
+static void pvr2_context_trigger_poll(struct pvr2_context *mp)
+{
+       queue_work(mp->workqueue,&mp->workpoll);
+}
+
+
+static void pvr2_context_poll(struct pvr2_context *mp)
+{
+       pvr2_context_enter(mp); do {
+               pvr2_hdw_poll(mp->hdw);
+       } while (0); pvr2_context_exit(mp);
+}
+
+
+static void pvr2_context_setup(struct pvr2_context *mp)
+{
+       pvr2_context_enter(mp); do {
+               if (!pvr2_hdw_dev_ok(mp->hdw)) break;
+               pvr2_hdw_setup(mp->hdw);
+               pvr2_hdw_setup_poll_trigger(
+                       mp->hdw,
+                       (void (*)(void *))pvr2_context_trigger_poll,
+                       mp);
+               if (!pvr2_hdw_dev_ok(mp->hdw)) break;
+               if (!pvr2_hdw_init_ok(mp->hdw)) break;
+               mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
+               if (mp->setup_func) {
+                       mp->setup_func(mp);
+               }
+       } while (0); pvr2_context_exit(mp);
+}
+
+
+struct pvr2_context *pvr2_context_create(
+       struct usb_interface *intf,
+       const struct usb_device_id *devid,
+       void (*setup_func)(struct pvr2_context *))
+{
+       struct pvr2_context *mp = 0;
+       mp = kmalloc(sizeof(*mp),GFP_KERNEL);
+       if (!mp) goto done;
+       memset(mp,0,sizeof(*mp));
+       pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
+       mp->setup_func = setup_func;
+       mutex_init(&mp->mutex);
+       mp->hdw = pvr2_hdw_create(intf,devid);
+       if (!mp->hdw) {
+               pvr2_context_destroy(mp);
+               mp = 0;
+               goto done;
+       }
+
+       mp->workqueue = create_singlethread_workqueue("pvrusb2");
+       INIT_WORK(&mp->workinit,(void (*)(void*))pvr2_context_setup,mp);
+       INIT_WORK(&mp->workpoll,(void (*)(void*))pvr2_context_poll,mp);
+       queue_work(mp->workqueue,&mp->workinit);
+ done:
+       return mp;
+}
+
+
+void pvr2_context_enter(struct pvr2_context *mp)
+{
+       mutex_lock(&mp->mutex);
+       pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp);
+}
+
+
+void pvr2_context_exit(struct pvr2_context *mp)
+{
+       int destroy_flag = 0;
+       if (!(mp->mc_first || !mp->disconnect_flag)) {
+               destroy_flag = !0;
+       }
+       pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp);
+       mutex_unlock(&mp->mutex);
+       if (destroy_flag) pvr2_context_destroy(mp);
+}
+
+
+static void pvr2_context_run_checks(struct pvr2_context *mp)
+{
+       struct pvr2_channel *ch1,*ch2;
+       for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
+               ch2 = ch1->mc_next;
+               if (ch1->check_func) {
+                       ch1->check_func(ch1);
+               }
+       }
+}
+
+
+void pvr2_context_disconnect(struct pvr2_context *mp)
+{
+       pvr2_context_enter(mp); do {
+               pvr2_hdw_disconnect(mp->hdw);
+               mp->disconnect_flag = !0;
+               pvr2_context_run_checks(mp);
+       } while (0); pvr2_context_exit(mp);
+}
+
+
+void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
+{
+       cp->hdw = mp->hdw;
+       cp->mc_head = mp;
+       cp->mc_next = 0;
+       cp->mc_prev = mp->mc_last;
+       if (mp->mc_last) {
+               mp->mc_last->mc_next = cp;
+       } else {
+               mp->mc_first = cp;
+       }
+       mp->mc_last = cp;
+}
+
+
+static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
+{
+       if (!cp->stream) return;
+       pvr2_stream_kill(cp->stream->stream);
+       cp->stream->user = 0;
+       cp->stream = 0;
+}
+
+
+void pvr2_channel_done(struct pvr2_channel *cp)
+{
+       struct pvr2_context *mp = cp->mc_head;
+       pvr2_channel_disclaim_stream(cp);
+       if (cp->mc_next) {
+               cp->mc_next->mc_prev = cp->mc_prev;
+       } else {
+               mp->mc_last = cp->mc_prev;
+       }
+       if (cp->mc_prev) {
+               cp->mc_prev->mc_next = cp->mc_next;
+       } else {
+               mp->mc_first = cp->mc_next;
+       }
+       cp->hdw = 0;
+}
+
+
+int pvr2_channel_claim_stream(struct pvr2_channel *cp,
+                             struct pvr2_context_stream *sp)
+{
+       int code = 0;
+       pvr2_context_enter(cp->mc_head); do {
+               if (sp == cp->stream) break;
+               if (sp->user) {
+                       code = -EBUSY;
+                       break;
+               }
+               pvr2_channel_disclaim_stream(cp);
+               if (!sp) break;
+               sp->user = cp;
+               cp->stream = sp;
+       } while (0); pvr2_context_exit(cp->mc_head);
+       return code;
+}
+
+
+// This is the marker for the real beginning of a legitimate mpeg2 stream.
+static char stream_sync_key[] = {
+       0x00, 0x00, 0x01, 0xba,
+};
+
+struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
+       struct pvr2_context_stream *sp)
+{
+       struct pvr2_ioread *cp;
+       cp = pvr2_ioread_create();
+       if (!cp) return 0;
+       pvr2_ioread_setup(cp,sp->stream);
+       pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
+       return cp;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h
new file mode 100644 (file)
index 0000000..6327fa1
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_BASE_H
+#define __PVRUSB2_BASE_H
+
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+
+struct pvr2_hdw;     /* hardware interface - defined elsewhere */
+struct pvr2_stream;  /* stream interface - defined elsewhere */
+
+struct pvr2_context;        /* All central state */
+struct pvr2_channel;        /* One I/O pathway to a user */
+struct pvr2_context_stream; /* Wrapper for a stream */
+struct pvr2_crit_reg;       /* Critical region pointer */
+struct pvr2_ioread;         /* Low level stream structure */
+
+struct pvr2_context_stream {
+       struct pvr2_channel *user;
+       struct pvr2_stream *stream;
+};
+
+struct pvr2_context {
+       struct pvr2_channel *mc_first;
+       struct pvr2_channel *mc_last;
+       struct pvr2_hdw *hdw;
+       struct pvr2_context_stream video_stream;
+       struct mutex mutex;
+       int disconnect_flag;
+
+       /* Called after pvr2_context initialization is complete */
+       void (*setup_func)(struct pvr2_context *);
+
+       /* Work queue overhead for out-of-line processing */
+       struct workqueue_struct *workqueue;
+       struct work_struct workinit;
+       struct work_struct workpoll;
+};
+
+struct pvr2_channel {
+       struct pvr2_context *mc_head;
+       struct pvr2_channel *mc_next;
+       struct pvr2_channel *mc_prev;
+       struct pvr2_context_stream *stream;
+       struct pvr2_hdw *hdw;
+       void (*check_func)(struct pvr2_channel *);
+};
+
+void pvr2_context_enter(struct pvr2_context *);
+void pvr2_context_exit(struct pvr2_context *);
+
+struct pvr2_context *pvr2_context_create(struct usb_interface *intf,
+                                        const struct usb_device_id *devid,
+                                        void (*setup_func)(struct pvr2_context *));
+void pvr2_context_disconnect(struct pvr2_context *);
+
+void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *);
+void pvr2_channel_done(struct pvr2_channel *);
+int pvr2_channel_claim_stream(struct pvr2_channel *,
+                             struct pvr2_context_stream *);
+struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
+       struct pvr2_context_stream *);
+
+
+#endif /* __PVRUSB2_CONTEXT_H */
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
new file mode 100644 (file)
index 0000000..d5df9fb
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 "pvrusb2-ctrl.h"
+#include "pvrusb2-hdw-internal.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+
+
+/* Set the given control. */
+int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
+{
+       return pvr2_ctrl_set_mask_value(cptr,~0,val);
+}
+
+
+/* Set/clear specific bits of the given control. */
+int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
+{
+       int ret = 0;
+       if (!cptr) return -EINVAL;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->set_value != 0) {
+                       if (cptr->info->type == pvr2_ctl_bitmask) {
+                               mask &= cptr->info->def.type_bitmask.valid_bits;
+                       } else if (cptr->info->type == pvr2_ctl_int) {
+                               if (val < cptr->info->def.type_int.min_value) {
+                                       break;
+                               }
+                               if (val > cptr->info->def.type_int.max_value) {
+                                       break;
+                               }
+                       } else if (cptr->info->type == pvr2_ctl_enum) {
+                               if (val >= cptr->info->def.type_enum.count) {
+                                       break;
+                               }
+                       } else if (cptr->info->type != pvr2_ctl_bool) {
+                               break;
+                       }
+                       ret = cptr->info->set_value(cptr,mask,val);
+               } else {
+                       ret = -EPERM;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Get the current value of the given control. */
+int pvr2_ctrl_get_value(struct pvr2_ctrl *cptr,int *valptr)
+{
+       int ret = 0;
+       if (!cptr) return -EINVAL;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               ret = cptr->info->get_value(cptr,valptr);
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve control's type */
+enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return pvr2_ctl_int;
+       return cptr->info->type;
+}
+
+
+/* Retrieve control's maximum value (int type) */
+int pvr2_ctrl_get_max(struct pvr2_ctrl *cptr)
+{
+       int ret = 0;
+       if (!cptr) return 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_int) {
+                       ret = cptr->info->def.type_int.max_value;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve control's minimum value (int type) */
+int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr)
+{
+       int ret = 0;
+       if (!cptr) return 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_int) {
+                       ret = cptr->info->def.type_int.min_value;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve control's default value (any type) */
+int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr)
+{
+       int ret = 0;
+       if (!cptr) return 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_int) {
+                       ret = cptr->info->default_value;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve control's enumeration count (enum only) */
+int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr)
+{
+       int ret = 0;
+       if (!cptr) return 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_enum) {
+                       ret = cptr->info->def.type_enum.count;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve control's valid mask bits (bit mask only) */
+int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr)
+{
+       int ret = 0;
+       if (!cptr) return 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_bitmask) {
+                       ret = cptr->info->def.type_bitmask.valid_bits;
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Retrieve the control's name */
+const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return 0;
+       return cptr->info->name;
+}
+
+
+/* Retrieve the control's desc */
+const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return 0;
+       return cptr->info->desc;
+}
+
+
+/* Retrieve a control enumeration or bit mask value */
+int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
+                         char *bptr,unsigned int bmax,
+                         unsigned int *blen)
+{
+       int ret = -EINVAL;
+       if (!cptr) return 0;
+       *blen = 0;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_enum) {
+                       const char **names;
+                       names = cptr->info->def.type_enum.value_names;
+                       if ((val >= 0) &&
+                           (val < cptr->info->def.type_enum.count)) {
+                               if (names[val]) {
+                                       *blen = scnprintf(
+                                               bptr,bmax,"%s",
+                                               names[val]);
+                               } else {
+                                       *blen = 0;
+                               }
+                               ret = 0;
+                       }
+               } else if (cptr->info->type == pvr2_ctl_bitmask) {
+                       const char **names;
+                       unsigned int idx;
+                       int msk;
+                       names = cptr->info->def.type_bitmask.bit_names;
+                       val &= cptr->info->def.type_bitmask.valid_bits;
+                       for (idx = 0, msk = 1; val; idx++, msk <<= 1) {
+                               if (val & msk) {
+                                       *blen = scnprintf(bptr,bmax,"%s",
+                                                         names[idx]);
+                                       ret = 0;
+                                       break;
+                               }
+                       }
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Return V4L ID for this control or zero if none */
+int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return 0;
+       return cptr->info->v4l_id;
+}
+
+
+unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr)
+{
+       unsigned int flags = 0;
+
+       if (cptr->info->get_v4lflags) {
+               flags = cptr->info->get_v4lflags(cptr);
+       }
+
+       if (cptr->info->set_value) {
+               flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
+       } else {
+               flags |= V4L2_CTRL_FLAG_READ_ONLY;
+       }
+
+       return flags;
+}
+
+
+/* Return true if control is writable */
+int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return 0;
+       return cptr->info->set_value != 0;
+}
+
+
+/* Return true if control has custom symbolic representation */
+int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr)
+{
+       if (!cptr) return 0;
+       if (!cptr->info->val_to_sym) return 0;
+       if (!cptr->info->sym_to_val) return 0;
+       return !0;
+}
+
+
+/* Convert a given mask/val to a custom symbolic value */
+int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr,
+                                 int mask,int val,
+                                 char *buf,unsigned int maxlen,
+                                 unsigned int *len)
+{
+       if (!cptr) return -EINVAL;
+       if (!cptr->info->val_to_sym) return -EINVAL;
+       return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len);
+}
+
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr,
+                                 const char *buf,unsigned int len,
+                                 int *maskptr,int *valptr)
+{
+       if (!cptr) return -EINVAL;
+       if (!cptr->info->sym_to_val) return -EINVAL;
+       return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr);
+}
+
+
+static unsigned int gen_bitmask_string(int msk,int val,int msk_only,
+                                      const char **names,
+                                      char *ptr,unsigned int len)
+{
+       unsigned int idx;
+       long sm,um;
+       int spcFl;
+       unsigned int uc,cnt;
+       const char *idStr;
+
+       spcFl = 0;
+       uc = 0;
+       um = 0;
+       for (idx = 0, sm = 1; msk; idx++, sm <<= 1) {
+               if (sm & msk) {
+                       msk &= ~sm;
+                       idStr = names[idx];
+                       if (idStr) {
+                               cnt = scnprintf(ptr,len,"%s%s%s",
+                                               (spcFl ? " " : ""),
+                                               (msk_only ? "" :
+                                                ((val & sm) ? "+" : "-")),
+                                               idStr);
+                               ptr += cnt; len -= cnt; uc += cnt;
+                               spcFl = !0;
+                       } else {
+                               um |= sm;
+                       }
+               }
+       }
+       if (um) {
+               if (msk_only) {
+                       cnt = scnprintf(ptr,len,"%s0x%lx",
+                                       (spcFl ? " " : ""),
+                                       um);
+                       ptr += cnt; len -= cnt; uc += cnt;
+                       spcFl = !0;
+               } else if (um & val) {
+                       cnt = scnprintf(ptr,len,"%s+0x%lx",
+                                       (spcFl ? " " : ""),
+                                       um & val);
+                       ptr += cnt; len -= cnt; uc += cnt;
+                       spcFl = !0;
+               } else if (um & ~val) {
+                       cnt = scnprintf(ptr,len,"%s+0x%lx",
+                                       (spcFl ? " " : ""),
+                                       um & ~val);
+                       ptr += cnt; len -= cnt; uc += cnt;
+                       spcFl = !0;
+               }
+       }
+       return uc;
+}
+
+
+static const char *boolNames[] = {
+       "false",
+       "true",
+       "no",
+       "yes",
+};
+
+
+static int parse_token(const char *ptr,unsigned int len,
+                      int *valptr,
+                      const char **names,unsigned int namecnt)
+{
+       char buf[33];
+       unsigned int slen;
+       unsigned int idx;
+       int negfl;
+       char *p2;
+       *valptr = 0;
+       if (!names) namecnt = 0;
+       for (idx = 0; idx < namecnt; idx++) {
+               if (!names[idx]) continue;
+               slen = strlen(names[idx]);
+               if (slen != len) continue;
+               if (memcmp(names[idx],ptr,slen)) continue;
+               *valptr = idx;
+               return 0;
+       }
+       negfl = 0;
+       if ((*ptr == '-') || (*ptr == '+')) {
+               negfl = (*ptr == '-');
+               ptr++; len--;
+       }
+       if (len >= sizeof(buf)) return -EINVAL;
+       memcpy(buf,ptr,len);
+       buf[len] = 0;
+       *valptr = simple_strtol(buf,&p2,0);
+       if (negfl) *valptr = -(*valptr);
+       if (*p2) return -EINVAL;
+       return 1;
+}
+
+
+static int parse_mtoken(const char *ptr,unsigned int len,
+                       int *valptr,
+                       const char **names,int valid_bits)
+{
+       char buf[33];
+       unsigned int slen;
+       unsigned int idx;
+       char *p2;
+       int msk;
+       *valptr = 0;
+       for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
+               if (!msk & valid_bits) continue;
+               valid_bits &= ~msk;
+               if (!names[idx]) continue;
+               slen = strlen(names[idx]);
+               if (slen != len) continue;
+               if (memcmp(names[idx],ptr,slen)) continue;
+               *valptr = msk;
+               return 0;
+       }
+       if (len >= sizeof(buf)) return -EINVAL;
+       memcpy(buf,ptr,len);
+       buf[len] = 0;
+       *valptr = simple_strtol(buf,&p2,0);
+       if (*p2) return -EINVAL;
+       return 0;
+}
+
+
+static int parse_tlist(const char *ptr,unsigned int len,
+                      int *maskptr,int *valptr,
+                      const char **names,int valid_bits)
+{
+       unsigned int cnt;
+       int mask,val,kv,mode,ret;
+       mask = 0;
+       val = 0;
+       ret = 0;
+       while (len) {
+               cnt = 0;
+               while ((cnt < len) &&
+                      ((ptr[cnt] <= 32) ||
+                       (ptr[cnt] >= 127))) cnt++;
+               ptr += cnt;
+               len -= cnt;
+               mode = 0;
+               if ((*ptr == '-') || (*ptr == '+')) {
+                       mode = (*ptr == '-') ? -1 : 1;
+                       ptr++;
+                       len--;
+               }
+               cnt = 0;
+               while (cnt < len) {
+                       if (ptr[cnt] <= 32) break;
+                       if (ptr[cnt] >= 127) break;
+                       cnt++;
+               }
+               if (!cnt) break;
+               if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ptr += cnt;
+               len -= cnt;
+               switch (mode) {
+               case 0:
+                       mask = valid_bits;
+                       val |= kv;
+                       break;
+               case -1:
+                       mask |= kv;
+                       val &= ~kv;
+                       break;
+               case 1:
+                       mask |= kv;
+                       val |= kv;
+                       break;
+               default:
+                       break;
+               }
+       }
+       *maskptr = mask;
+       *valptr = val;
+       return ret;
+}
+
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
+                          const char *ptr,unsigned int len,
+                          int *maskptr,int *valptr)
+{
+       int ret = -EINVAL;
+       unsigned int cnt;
+
+       *maskptr = 0;
+       *valptr = 0;
+
+       cnt = 0;
+       while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
+       len -= cnt; ptr += cnt;
+       cnt = 0;
+       while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
+                              (ptr[len-(cnt+1)] >= 127))) cnt++;
+       len -= cnt;
+
+       if (!len) return -EINVAL;
+
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               if (cptr->info->type == pvr2_ctl_int) {
+                       ret = parse_token(ptr,len,valptr,0,0);
+                       if ((ret >= 0) &&
+                           ((*valptr < cptr->info->def.type_int.min_value) ||
+                            (*valptr > cptr->info->def.type_int.max_value))) {
+                               ret = -ERANGE;
+                       }
+                       if (maskptr) *maskptr = ~0;
+               } else if (cptr->info->type == pvr2_ctl_bool) {
+                       ret = parse_token(
+                               ptr,len,valptr,boolNames,
+                               sizeof(boolNames)/sizeof(boolNames[0]));
+                       if (ret == 1) {
+                               *valptr = *valptr ? !0 : 0;
+                       } else if (ret == 0) {
+                               *valptr = (*valptr & 1) ? !0 : 0;
+                       }
+                       if (maskptr) *maskptr = 1;
+               } else if (cptr->info->type == pvr2_ctl_enum) {
+                       ret = parse_token(
+                               ptr,len,valptr,
+                               cptr->info->def.type_enum.value_names,
+                               cptr->info->def.type_enum.count);
+                       if ((ret >= 0) &&
+                           ((*valptr < 0) ||
+                            (*valptr >= cptr->info->def.type_enum.count))) {
+                               ret = -ERANGE;
+                       }
+                       if (maskptr) *maskptr = ~0;
+               } else if (cptr->info->type == pvr2_ctl_bitmask) {
+                       ret = parse_tlist(
+                               ptr,len,maskptr,valptr,
+                               cptr->info->def.type_bitmask.bit_names,
+                               cptr->info->def.type_bitmask.valid_bits);
+               }
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
+                                   int mask,int val,
+                                   char *buf,unsigned int maxlen,
+                                   unsigned int *len)
+{
+       int ret = -EINVAL;
+
+       *len = 0;
+       if (cptr->info->type == pvr2_ctl_int) {
+               *len = scnprintf(buf,maxlen,"%d",val);
+               ret = 0;
+       } else if (cptr->info->type == pvr2_ctl_bool) {
+               *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
+               ret = 0;
+       } else if (cptr->info->type == pvr2_ctl_enum) {
+               const char **names;
+               names = cptr->info->def.type_enum.value_names;
+               if ((val >= 0) &&
+                   (val < cptr->info->def.type_enum.count)) {
+                       if (names[val]) {
+                               *len = scnprintf(
+                                       buf,maxlen,"%s",
+                                       names[val]);
+                       } else {
+                               *len = 0;
+                       }
+                       ret = 0;
+               }
+       } else if (cptr->info->type == pvr2_ctl_bitmask) {
+               *len = gen_bitmask_string(
+                       val & mask & cptr->info->def.type_bitmask.valid_bits,
+                       ~0,!0,
+                       cptr->info->def.type_bitmask.bit_names,
+                       buf,maxlen);
+       }
+       return ret;
+}
+
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
+                          int mask,int val,
+                          char *buf,unsigned int maxlen,
+                          unsigned int *len)
+{
+       int ret;
+       LOCK_TAKE(cptr->hdw->big_lock); do {
+               ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
+                                                     buf,maxlen,len);
+       } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+       return ret;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
new file mode 100644 (file)
index 0000000..c168005
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_CTRL_H
+#define __PVRUSB2_CTRL_H
+
+struct pvr2_ctrl;
+
+enum pvr2_ctl_type {
+       pvr2_ctl_int = 0,
+       pvr2_ctl_enum = 1,
+       pvr2_ctl_bitmask = 2,
+       pvr2_ctl_bool = 3,
+};
+
+
+/* Set the given control. */
+int pvr2_ctrl_set_value(struct pvr2_ctrl *,int val);
+
+/* Set/clear specific bits of the given control. */
+int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *,int mask,int val);
+
+/* Get the current value of the given control. */
+int pvr2_ctrl_get_value(struct pvr2_ctrl *,int *valptr);
+
+/* Retrieve control's type */
+enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *);
+
+/* Retrieve control's maximum value (int type) */
+int pvr2_ctrl_get_max(struct pvr2_ctrl *);
+
+/* Retrieve control's minimum value (int type) */
+int pvr2_ctrl_get_min(struct pvr2_ctrl *);
+
+/* Retrieve control's default value (any type) */
+int pvr2_ctrl_get_def(struct pvr2_ctrl *);
+
+/* Retrieve control's enumeration count (enum only) */
+int pvr2_ctrl_get_cnt(struct pvr2_ctrl *);
+
+/* Retrieve control's valid mask bits (bit mask only) */
+int pvr2_ctrl_get_mask(struct pvr2_ctrl *);
+
+/* Retrieve the control's name */
+const char *pvr2_ctrl_get_name(struct pvr2_ctrl *);
+
+/* Retrieve the control's desc */
+const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *);
+
+/* Retrieve a control enumeration or bit mask value */
+int pvr2_ctrl_get_valname(struct pvr2_ctrl *,int,char *,unsigned int,
+                         unsigned int *);
+
+/* Return true if control is writable */
+int pvr2_ctrl_is_writable(struct pvr2_ctrl *);
+
+/* Return V4L flags value for control (or zero if there is no v4l control
+   actually under this control) */
+unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *);
+
+/* Return V4L ID for this control or zero if none */
+int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *);
+
+/* Return true if control has custom symbolic representation */
+int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *);
+
+/* Convert a given mask/val to a custom symbolic value */
+int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *,
+                                 int mask,int val,
+                                 char *buf,unsigned int maxlen,
+                                 unsigned int *len);
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *,
+                                 const char *buf,unsigned int len,
+                                 int *maskptr,int *valptr);
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *,
+                          int mask,int val,
+                          char *buf,unsigned int maxlen,
+                          unsigned int *len);
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *,
+                          const char *buf,unsigned int len,
+                          int *maskptr,int *valptr);
+
+/* Convert a given mask/val to a symbolic value - must already be
+   inside of critical region. */
+int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *,
+                          int mask,int val,
+                          char *buf,unsigned int maxlen,
+                          unsigned int *len);
+
+#endif /* __PVRUSB2_CTRL_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
new file mode 100644 (file)
index 0000000..27eadaf
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+
+   This source file is specifically designed to interface with the
+   cx2584x, in kernels 2.6.16 or newer.
+
+*/
+
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <media/cx25840.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_cx2584x {
+       struct pvr2_i2c_handler handler;
+       struct pvr2_decoder_ctrl ctrl;
+       struct pvr2_i2c_client *client;
+       struct pvr2_hdw *hdw;
+       unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_cx2584x *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       struct v4l2_routing route;
+       enum cx25840_video_input vid_input;
+       enum cx25840_audio_input aud_input;
+
+       memset(&route,0,sizeof(route));
+
+       switch(hdw->input_val) {
+       case PVR2_CVAL_INPUT_TV:
+               vid_input = CX25840_COMPOSITE7;
+               aud_input = CX25840_AUDIO8;
+               break;
+       case PVR2_CVAL_INPUT_COMPOSITE:
+               vid_input = CX25840_COMPOSITE3;
+               aud_input = CX25840_AUDIO_SERIAL;
+               break;
+       case PVR2_CVAL_INPUT_SVIDEO:
+               vid_input = CX25840_SVIDEO1;
+               aud_input = CX25840_AUDIO_SERIAL;
+               break;
+       case PVR2_CVAL_INPUT_RADIO:
+       default:
+               // Just set it to be composite input for now...
+               vid_input = CX25840_COMPOSITE3;
+               aud_input = CX25840_AUDIO_SERIAL;
+               break;
+       }
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
+                  vid_input,aud_input);
+       route.input = (u32)vid_input;
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
+       route.input = (u32)aud_input;
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+
+static int check_input(struct pvr2_v4l_cx2584x *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return hdw->input_dirty != 0;
+}
+
+
+static void set_audio(struct pvr2_v4l_cx2584x *ctxt)
+{
+       u32 val;
+       struct pvr2_hdw *hdw = ctxt->hdw;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_audio %d",
+                  hdw->srate_val);
+       switch (hdw->srate_val) {
+       default:
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+               val = 48000;
+               break;
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+               val = 44100;
+               break;
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+               val = 32000;
+               break;
+       }
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
+}
+
+
+static int check_audio(struct pvr2_v4l_cx2584x *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return hdw->srate_dirty != 0;
+}
+
+
+struct pvr2_v4l_cx2584x_ops {
+       void (*update)(struct pvr2_v4l_cx2584x *);
+       int (*check)(struct pvr2_v4l_cx2584x *);
+};
+
+
+static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
+       { .update = set_input, .check = check_input},
+       { .update = set_audio, .check = check_audio},
+};
+
+
+static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
+{
+       ctxt->client->handler = 0;
+       ctxt->hdw->decoder_ctrl = 0;
+       kfree(ctxt);
+}
+
+
+static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (ctxt->stale_mask & msk) continue;
+               if (decoder_ops[idx].check(ctxt)) {
+                       ctxt->stale_mask |= msk;
+               }
+       }
+       return ctxt->stale_mask != 0;
+}
+
+
+static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (!(ctxt->stale_mask & msk)) continue;
+               ctxt->stale_mask &= ~msk;
+               decoder_ops[idx].update(ctxt);
+       }
+}
+
+
+static void decoder_enable(struct pvr2_v4l_cx2584x *ctxt,int fl)
+{
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_enable(%d)",fl);
+       pvr2_v4l2_cmd_stream(ctxt->client,fl);
+}
+
+
+static int decoder_detect(struct pvr2_i2c_client *cp)
+{
+       int ret;
+       /* Attempt to query the decoder - let's see if it will answer */
+       struct v4l2_queryctrl qc;
+
+       memset(&qc,0,sizeof(qc));
+
+       qc.id = V4L2_CID_BRIGHTNESS;
+
+       ret = pvr2_i2c_client_cmd(cp,VIDIOC_QUERYCTRL,&qc);
+       return ret == 0; /* Return true if it answered */
+}
+
+
+static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt)
+{
+       struct v4l2_tuner vt;
+       int ret;
+
+       memset(&vt,0,sizeof(vt));
+       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
+       if (ret < 0) return -EINVAL;
+       return vt.signal ? 1 : 0;
+}
+
+
+static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
+                                    char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-cx2584x-v4l");
+}
+
+
+static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
+{
+       int ret;
+       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,0);
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret);
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+       .detach = (void (*)(void *))decoder_detach,
+       .check = (int (*)(void *))decoder_check,
+       .update = (void (*)(void *))decoder_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
+};
+
+
+int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
+                              struct pvr2_i2c_client *cp)
+{
+       struct pvr2_v4l_cx2584x *ctxt;
+
+       if (hdw->decoder_ctrl) return 0;
+       if (cp->handler) return 0;
+       if (!decoder_detect(cp)) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->handler.func_data = ctxt;
+       ctxt->handler.func_table = &hfuncs;
+       ctxt->ctrl.ctxt = ctxt;
+       ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
+       ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
+       ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
+       ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
+                                 sizeof(decoder_ops[0]))) - 1;
+       hdw->decoder_ctrl = &ctxt->ctrl;
+       cp->handler = &ctxt->handler;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x cx2584x V4L2 handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
new file mode 100644 (file)
index 0000000..54b2844
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_CX2584X_V4L_H
+#define __PVRUSB2_CX2584X_V4L_H
+
+/*
+
+   This module connects the pvrusb2 driver to the I2C chip level
+   driver which handles combined device audio & video processing.
+   This interface is used internally by the driver; higher level code
+   should only interact through the interface provided by
+   pvrusb2-hdw.h.
+
+*/
+
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_CX2584X_V4L_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
new file mode 100644 (file)
index 0000000..d95a858
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_DEBUG_H
+#define __PVRUSB2_DEBUG_H
+
+extern int pvrusb2_debug;
+
+#define pvr2_trace(msk, fmt, arg...) do {if(msk & pvrusb2_debug) printk(KERN_INFO "pvrusb2: " fmt "\n", ##arg); } while (0)
+
+/* These are listed in *rough* order of decreasing usefulness and
+   increasing noise level. */
+#define PVR2_TRACE_INFO       (1 <<  0) // Normal messages
+#define PVR2_TRACE_ERROR_LEGS (1 <<  1) // error messages
+#define PVR2_TRACE_TOLERANCE  (1 <<  2) // track tolerance-affected errors
+#define PVR2_TRACE_TRAP       (1 <<  3) // Trap & report misbehavior from app
+#define PVR2_TRACE_INIT       (1 <<  4) // misc initialization steps
+#define PVR2_TRACE_START_STOP (1 <<  5) // Streaming start / stop
+#define PVR2_TRACE_CTL        (1 <<  6) // commit of control changes
+#define PVR2_TRACE_DEBUG      (1 <<  7) // Temporary debug code
+#define PVR2_TRACE_EEPROM     (1 <<  8) // eeprom parsing / report
+#define PVR2_TRACE_STRUCT     (1 <<  9) // internal struct creation
+#define PVR2_TRACE_OPEN_CLOSE (1 << 10) // application open / close
+#define PVR2_TRACE_CREG       (1 << 11) // Main critical region entry / exit
+#define PVR2_TRACE_SYSFS      (1 << 12) // Sysfs driven I/O
+#define PVR2_TRACE_FIRMWARE   (1 << 13) // firmware upload actions
+#define PVR2_TRACE_CHIPS      (1 << 14) // chip broadcast operation
+#define PVR2_TRACE_I2C        (1 << 15) // I2C related stuff
+#define PVR2_TRACE_I2C_CMD    (1 << 16) // Software commands to I2C modules
+#define PVR2_TRACE_I2C_CORE   (1 << 17) // I2C core debugging
+#define PVR2_TRACE_I2C_TRAF   (1 << 18) // I2C traffic through the adapter
+#define PVR2_TRACE_V4LIOCTL   (1 << 19) // v4l ioctl details
+#define PVR2_TRACE_ENCODER    (1 << 20) // mpeg2 encoder operation
+#define PVR2_TRACE_BUF_POOL   (1 << 21) // Track buffer pool management
+#define PVR2_TRACE_BUF_FLOW   (1 << 22) // Track buffer flow in system
+#define PVR2_TRACE_DATA_FLOW  (1 << 23) // Track data flow
+#define PVR2_TRACE_DEBUGIFC   (1 << 24) // Debug interface actions
+#define PVR2_TRACE_GPIO       (1 << 25) // GPIO state bit changes
+
+
+#endif /* __PVRUSB2_HDW_INTERNAL_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
new file mode 100644 (file)
index 0000000..586900e
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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/string.h>
+#include <linux/slab.h>
+#include "pvrusb2-debugifc.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-i2c-core.h"
+
+struct debugifc_mask_item {
+       const char *name;
+       unsigned long msk;
+};
+
+static struct debugifc_mask_item mask_items[] = {
+       {"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)},
+       {"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)},
+       {"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)},
+       {"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)},
+       {"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)},
+};
+
+
+static unsigned int debugifc_count_whitespace(const char *buf,
+                                             unsigned int count)
+{
+       unsigned int scnt;
+       char ch;
+
+       for (scnt = 0; scnt < count; scnt++) {
+               ch = buf[scnt];
+               if (ch == ' ') continue;
+               if (ch == '\t') continue;
+               if (ch == '\n') continue;
+               break;
+       }
+       return scnt;
+}
+
+
+static unsigned int debugifc_count_nonwhitespace(const char *buf,
+                                                unsigned int count)
+{
+       unsigned int scnt;
+       char ch;
+
+       for (scnt = 0; scnt < count; scnt++) {
+               ch = buf[scnt];
+               if (ch == ' ') break;
+               if (ch == '\t') break;
+               if (ch == '\n') break;
+       }
+       return scnt;
+}
+
+
+static unsigned int debugifc_isolate_word(const char *buf,unsigned int count,
+                                         const char **wstrPtr,
+                                         unsigned int *wlenPtr)
+{
+       const char *wptr;
+       unsigned int consume_cnt = 0;
+       unsigned int wlen;
+       unsigned int scnt;
+
+       wptr = 0;
+       wlen = 0;
+       scnt = debugifc_count_whitespace(buf,count);
+       consume_cnt += scnt; count -= scnt; buf += scnt;
+       if (!count) goto done;
+
+       scnt = debugifc_count_nonwhitespace(buf,count);
+       if (!scnt) goto done;
+       wptr = buf;
+       wlen = scnt;
+       consume_cnt += scnt; count -= scnt; buf += scnt;
+
+ done:
+       *wstrPtr = wptr;
+       *wlenPtr = wlen;
+       return consume_cnt;
+}
+
+
+static int debugifc_parse_unsigned_number(const char *buf,unsigned int count,
+                                         u32 *num_ptr)
+{
+       u32 result = 0;
+       u32 val;
+       int ch;
+       int radix = 10;
+       if ((count >= 2) && (buf[0] == '0') &&
+           ((buf[1] == 'x') || (buf[1] == 'X'))) {
+               radix = 16;
+               count -= 2;
+               buf += 2;
+       } else if ((count >= 1) && (buf[0] == '0')) {
+               radix = 8;
+       }
+
+       while (count--) {
+               ch = *buf++;
+               if ((ch >= '0') && (ch <= '9')) {
+                       val = ch - '0';
+               } else if ((ch >= 'a') && (ch <= 'f')) {
+                       val = ch - 'a' + 10;
+               } else if ((ch >= 'A') && (ch <= 'F')) {
+                       val = ch - 'A' + 10;
+               } else {
+                       return -EINVAL;
+               }
+               if (val >= radix) return -EINVAL;
+               result *= radix;
+               result += val;
+       }
+       *num_ptr = result;
+       return 0;
+}
+
+
+static int debugifc_match_keyword(const char *buf,unsigned int count,
+                                 const char *keyword)
+{
+       unsigned int kl;
+       if (!keyword) return 0;
+       kl = strlen(keyword);
+       if (kl != count) return 0;
+       return !memcmp(buf,keyword,kl);
+}
+
+
+static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
+{
+       struct debugifc_mask_item *mip;
+       unsigned int idx;
+       for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+               mip = mask_items + idx;
+               if (debugifc_match_keyword(buf,count,mip->name)) {
+                       return mip->msk;
+               }
+       }
+       return 0;
+}
+
+
+static int debugifc_print_mask(char *buf,unsigned int sz,
+                              unsigned long msk,unsigned long val)
+{
+       struct debugifc_mask_item *mip;
+       unsigned int idx;
+       int bcnt = 0;
+       int ccnt;
+       for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+               mip = mask_items + idx;
+               if (!(mip->msk & msk)) continue;
+               ccnt = scnprintf(buf,sz,"%s%c%s",
+                                (bcnt ? " " : ""),
+                                ((mip->msk & val) ? '+' : '-'),
+                                mip->name);
+               sz -= ccnt;
+               buf += ccnt;
+               bcnt += ccnt;
+       }
+       return bcnt;
+}
+
+static unsigned int debugifc_parse_subsys_mask(const char *buf,
+                                              unsigned int count,
+                                              unsigned long *mskPtr,
+                                              unsigned long *valPtr)
+{
+       const char *wptr;
+       unsigned int consume_cnt = 0;
+       unsigned int scnt;
+       unsigned int wlen;
+       int mode;
+       unsigned long m1,msk,val;
+
+       msk = 0;
+       val = 0;
+
+       while (count) {
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (!scnt) break;
+               consume_cnt += scnt; count -= scnt; buf += scnt;
+               if (!wptr) break;
+
+               mode = 0;
+               if (wlen) switch (wptr[0]) {
+               case '+':
+                       wptr++;
+                       wlen--;
+                       break;
+               case '-':
+                       mode = 1;
+                       wptr++;
+                       wlen--;
+                       break;
+               }
+               if (!wlen) continue;
+               m1 = debugifc_find_mask(wptr,wlen);
+               if (!m1) break;
+               msk |= m1;
+               if (!mode) val |= m1;
+       }
+       *mskPtr = msk;
+       *valPtr = val;
+       return consume_cnt;
+}
+
+
+int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
+{
+       int bcnt = 0;
+       int ccnt;
+       struct pvr2_hdw_debug_info dbg;
+
+       pvr2_hdw_get_debug_info(hdw,&dbg);
+
+       ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s",
+                        (dbg.big_lock_held ? "held" : "free"),
+                        (dbg.ctl_lock_held ? "held" : "free"));
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       if (dbg.ctl_lock_held) {
+               ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d"
+                                " cmd_wlen=%d cmd_rlen=%d"
+                                " wpend=%d rpend=%d tmout=%d rstatus=%d"
+                                " wstatus=%d",
+                                dbg.cmd_debug_state,dbg.cmd_code,
+                                dbg.cmd_debug_write_len,
+                                dbg.cmd_debug_read_len,
+                                dbg.cmd_debug_write_pend,
+                                dbg.cmd_debug_read_pend,
+                                dbg.cmd_debug_timeout,
+                                dbg.cmd_debug_rstatus,
+                                dbg.cmd_debug_wstatus);
+               bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       }
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(
+               buf,acnt,"driver flags: %s %s %s\n",
+               (dbg.flag_init_ok ? "initialized" : "uninitialized"),
+               (dbg.flag_ok ? "ok" : "fail"),
+               (dbg.flag_disconnected ? "disconnected" : "connected"));
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = pvr2_i2c_report(hdw,buf,acnt);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       return bcnt;
+}
+
+
+int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
+                              char *buf,unsigned int acnt)
+{
+       int bcnt = 0;
+       int ccnt;
+       unsigned long msk;
+       int ret;
+       u32 gpio_dir,gpio_in,gpio_out;
+
+       ret = pvr2_hdw_is_hsm(hdw);
+       ccnt = scnprintf(buf,acnt,"USB link speed: %s\n",
+                        (ret < 0 ? "FAIL" : (ret ? "high" : "full")));
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       gpio_dir = 0; gpio_in = 0; gpio_out = 0;
+       pvr2_hdw_gpio_get_dir(hdw,&gpio_dir);
+       pvr2_hdw_gpio_get_out(hdw,&gpio_out);
+       pvr2_hdw_gpio_get_in(hdw,&gpio_in);
+       ccnt = scnprintf(buf,acnt,"GPIO state: dir=0x%x in=0x%x out=0x%x\n",
+                        gpio_dir,gpio_in,gpio_out);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       ccnt = scnprintf(buf,acnt,"Streaming is %s\n",
+                        pvr2_hdw_get_streaming(hdw) ? "on" : "off");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       msk = pvr2_hdw_subsys_get(hdw);
+       ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = debugifc_print_mask(buf,acnt,msk,msk);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = debugifc_print_mask(buf,acnt,~msk,msk);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       msk = pvr2_hdw_subsys_stream_get(hdw);
+       ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: ");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = debugifc_print_mask(buf,acnt,msk,msk);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+       ccnt = scnprintf(buf,acnt,"\n");
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+       return bcnt;
+}
+
+
+int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
+                        unsigned int count)
+{
+       const char *wptr;
+       unsigned int wlen;
+       unsigned int scnt;
+
+       scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+       if (!scnt) return 0;
+       count -= scnt; buf += scnt;
+       if (!wptr) return 0;
+
+       pvr2_trace(PVR2_TRACE_DEBUGIFC,"debugifc cmd: \"%.*s\"",wlen,wptr);
+       if (debugifc_match_keyword(wptr,wlen,"reset")) {
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (!scnt) return -EINVAL;
+               count -= scnt; buf += scnt;
+               if (!wptr) return -EINVAL;
+               if (debugifc_match_keyword(wptr,wlen,"cpu")) {
+                       pvr2_hdw_cpureset_assert(hdw,!0);
+                       pvr2_hdw_cpureset_assert(hdw,0);
+                       return 0;
+               } else if (debugifc_match_keyword(wptr,wlen,"bus")) {
+                       pvr2_hdw_device_reset(hdw);
+               } else if (debugifc_match_keyword(wptr,wlen,"soft")) {
+                       return pvr2_hdw_cmd_powerup(hdw);
+               } else if (debugifc_match_keyword(wptr,wlen,"deep")) {
+                       return pvr2_hdw_cmd_deep_reset(hdw);
+               } else if (debugifc_match_keyword(wptr,wlen,"firmware")) {
+                       return pvr2_upload_firmware2(hdw);
+               } else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
+                       return pvr2_hdw_cmd_decoder_reset(hdw);
+               }
+               return -EINVAL;
+       } else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
+               unsigned long msk = 0;
+               unsigned long val = 0;
+               if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
+                       pvr2_trace(PVR2_TRACE_DEBUGIFC,
+                                  "debugifc parse error on subsys mask");
+                       return -EINVAL;
+               }
+               pvr2_hdw_subsys_bit_chg(hdw,msk,val);
+               return 0;
+       } else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) {
+               unsigned long msk = 0;
+               unsigned long val = 0;
+               if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
+                       pvr2_trace(PVR2_TRACE_DEBUGIFC,
+                                  "debugifc parse error on stream mask");
+                       return -EINVAL;
+               }
+               pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val);
+               return 0;
+       } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (!scnt) return -EINVAL;
+               count -= scnt; buf += scnt;
+               if (!wptr) return -EINVAL;
+               if (debugifc_match_keyword(wptr,wlen,"fetch")) {
+                       pvr2_hdw_cpufw_set_enabled(hdw,!0);
+                       return 0;
+               } else if (debugifc_match_keyword(wptr,wlen,"done")) {
+                       pvr2_hdw_cpufw_set_enabled(hdw,0);
+                       return 0;
+               } else {
+                       return -EINVAL;
+               }
+       } else if (debugifc_match_keyword(wptr,wlen,"gpio")) {
+               int dir_fl = 0;
+               int ret;
+               u32 msk,val;
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (!scnt) return -EINVAL;
+               count -= scnt; buf += scnt;
+               if (!wptr) return -EINVAL;
+               if (debugifc_match_keyword(wptr,wlen,"dir")) {
+                       dir_fl = !0;
+               } else if (!debugifc_match_keyword(wptr,wlen,"out")) {
+                       return -EINVAL;
+               }
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (!scnt) return -EINVAL;
+               count -= scnt; buf += scnt;
+               if (!wptr) return -EINVAL;
+               ret = debugifc_parse_unsigned_number(wptr,wlen,&msk);
+               if (ret) return ret;
+               scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+               if (wptr) {
+                       ret = debugifc_parse_unsigned_number(wptr,wlen,&val);
+                       if (ret) return ret;
+               } else {
+                       val = msk;
+                       msk = 0xffffffff;
+               }
+               if (dir_fl) {
+                       ret = pvr2_hdw_gpio_chg_dir(hdw,msk,val);
+               } else {
+                       ret = pvr2_hdw_gpio_chg_out(hdw,msk,val);
+               }
+               return ret;
+       }
+       pvr2_trace(PVR2_TRACE_DEBUGIFC,
+                  "debugifc failed to recognize cmd: \"%.*s\"",wlen,wptr);
+       return -EINVAL;
+}
+
+
+int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf,
+                       unsigned int count)
+{
+       unsigned int bcnt = 0;
+       int ret;
+
+       while (count) {
+               for (bcnt = 0; bcnt < count; bcnt++) {
+                       if (buf[bcnt] == '\n') break;
+               }
+
+               ret = pvr2_debugifc_do1cmd(hdw,buf,bcnt);
+               if (ret < 0) return ret;
+               if (bcnt < count) bcnt++;
+               buf += bcnt;
+               count -= bcnt;
+       }
+
+       return 0;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
new file mode 100644 (file)
index 0000000..990b02d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_DEBUGIFC_H
+#define __PVRUSB2_DEBUGIFC_H
+
+struct pvr2_hdw;
+
+/* Non-intrusively print some useful debugging info from inside the
+   driver.  This should work even if the driver appears to be
+   wedged. */
+int pvr2_debugifc_print_info(struct pvr2_hdw *,
+                            char *buf_ptr,unsigned int buf_size);
+
+/* Print general status of driver.  This will also trigger a probe of
+   the USB link.  Unlike print_info(), this one synchronizes with the
+   driver so the information should be self-consistent (but it will
+   hang if the driver is wedged). */
+int pvr2_debugifc_print_status(struct pvr2_hdw *,
+                              char *buf_ptr,unsigned int buf_size);
+
+/* Parse a string command into a driver action. */
+int pvr2_debugifc_docmd(struct pvr2_hdw *,
+                       const char *buf_ptr,unsigned int buf_size);
+
+#endif /* __PVRUSB2_DEBUGIFC_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-demod.c b/drivers/media/video/pvrusb2/pvrusb2-demod.c
new file mode 100644 (file)
index 0000000..9686569
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2.h"
+#include "pvrusb2-util.h"
+#include "pvrusb2-demod.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+
+
+struct pvr2_demod_handler {
+       struct pvr2_hdw *hdw;
+       struct pvr2_i2c_client *client;
+       struct pvr2_i2c_handler i2c_handler;
+       int type_update_fl;
+};
+
+
+static void set_config(struct pvr2_demod_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       int cfg = 0;
+
+       switch (hdw->tuner_type) {
+       case TUNER_PHILIPS_FM1216ME_MK3:
+       case TUNER_PHILIPS_FM1236_MK3:
+               cfg = TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE;
+               break;
+       default:
+               break;
+       }
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c demod set_config(0x%x)",cfg);
+       pvr2_i2c_client_cmd(ctxt->client,TDA9887_SET_CONFIG,&cfg);
+       ctxt->type_update_fl = 0;
+}
+
+
+static int demod_check(struct pvr2_demod_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       if (hdw->tuner_updated) ctxt->type_update_fl = !0;
+       return ctxt->type_update_fl != 0;
+}
+
+
+static void demod_update(struct pvr2_demod_handler *ctxt)
+{
+       if (ctxt->type_update_fl) set_config(ctxt);
+}
+
+
+static void demod_detach(struct pvr2_demod_handler *ctxt)
+{
+       ctxt->client->handler = 0;
+       kfree(ctxt);
+}
+
+
+static unsigned int demod_describe(struct pvr2_demod_handler *ctxt,char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-demod");
+}
+
+
+const static struct pvr2_i2c_handler_functions tuner_funcs = {
+       .detach = (void (*)(void *))demod_detach,
+       .check = (int (*)(void *))demod_check,
+       .update = (void (*)(void *))demod_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))demod_describe,
+};
+
+
+int pvr2_i2c_demod_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+       struct pvr2_demod_handler *ctxt;
+       if (cp->handler) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->i2c_handler.func_data = ctxt;
+       ctxt->i2c_handler.func_table = &tuner_funcs;
+       ctxt->type_update_fl = !0;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       cp->handler = &ctxt->i2c_handler;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x tda9887 V4L2 handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-demod.h b/drivers/media/video/pvrusb2/pvrusb2-demod.h
new file mode 100644 (file)
index 0000000..4c4e40f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_DEMOD_H
+#define __PVRUSB2_DEMOD_H
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_demod_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+#endif /* __PVRUSB2_DEMOD_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
new file mode 100644 (file)
index 0000000..94d383f
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-eeprom.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+
+#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__)
+
+
+
+/*
+
+   Read and analyze data in the eeprom.  Use tveeprom to figure out
+   the packet structure, since this is another Hauppauge device and
+   internally it has a family resemblence to ivtv-type devices
+
+*/
+
+#include <media/tveeprom.h>
+
+/* We seem to only be interested in the last 128 bytes of the EEPROM */
+#define EEPROM_SIZE 128
+
+/* Grab EEPROM contents, needed for direct method. */
+static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
+{
+       struct i2c_msg msg[2];
+       u8 *eeprom;
+       u8 iadd[2];
+       u8 addr;
+       u16 eepromSize;
+       unsigned int offs;
+       int ret;
+       int mode16 = 0;
+       unsigned pcnt,tcnt;
+       eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL);
+       if (!eeprom) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to allocate memory"
+                          " required to read eeprom");
+               return 0;
+       }
+
+       trace_eeprom("Value for eeprom addr from controller was 0x%x",
+                    hdw->eeprom_addr);
+       addr = hdw->eeprom_addr;
+       /* Seems that if the high bit is set, then the *real* eeprom
+          address is shifted right now bit position (noticed this in
+          newer PVR USB2 hardware) */
+       if (addr & 0x80) addr >>= 1;
+
+       /* FX2 documentation states that a 16bit-addressed eeprom is
+          expected if the I2C address is an odd number (yeah, this is
+          strange but it's what they do) */
+       mode16 = (addr & 1);
+       eepromSize = (mode16 ? 4096 : 256);
+       trace_eeprom("Examining %d byte eeprom at location 0x%x"
+                    " using %d bit addressing",eepromSize,addr,
+                    mode16 ? 16 : 8);
+
+       msg[0].addr = addr;
+       msg[0].flags = 0;
+       msg[0].len = mode16 ? 2 : 1;
+       msg[0].buf = iadd;
+       msg[1].addr = addr;
+       msg[1].flags = I2C_M_RD;
+
+       /* We have to do the actual eeprom data fetch ourselves, because
+          (1) we're only fetching part of the eeprom, and (2) if we were
+          getting the whole thing our I2C driver can't grab it in one
+          pass - which is what tveeprom is otherwise going to attempt */
+       memset(eeprom,0,EEPROM_SIZE);
+       for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) {
+               pcnt = 16;
+               if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt;
+               offs = tcnt + (eepromSize - EEPROM_SIZE);
+               if (mode16) {
+                       iadd[0] = offs >> 8;
+                       iadd[1] = offs;
+               } else {
+                       iadd[0] = offs;
+               }
+               msg[1].len = pcnt;
+               msg[1].buf = eeprom+tcnt;
+               if ((ret = i2c_transfer(
+                            &hdw->i2c_adap,
+                            msg,sizeof(msg)/sizeof(msg[0]))) != 2) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "eeprom fetch set offs err=%d",ret);
+                       kfree(eeprom);
+                       return 0;
+               }
+       }
+       return eeprom;
+}
+
+
+/* Directly call eeprom analysis function within tveeprom. */
+int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
+{
+       u8 *eeprom;
+       struct tveeprom tvdata;
+
+       memset(&tvdata,0,sizeof(tvdata));
+
+       eeprom = pvr2_eeprom_fetch(hdw);
+       if (!eeprom) return -EINVAL;
+
+       {
+               struct i2c_client fake_client;
+               /* Newer version expects a useless client interface */
+               fake_client.addr = hdw->eeprom_addr;
+               fake_client.adapter = &hdw->i2c_adap;
+               tveeprom_hauppauge_analog(&fake_client,&tvdata,eeprom);
+       }
+
+       trace_eeprom("eeprom assumed v4l tveeprom module");
+       trace_eeprom("eeprom direct call results:");
+       trace_eeprom("has_radio=%d",tvdata.has_radio);
+       trace_eeprom("tuner_type=%d",tvdata.tuner_type);
+       trace_eeprom("tuner_formats=0x%x",tvdata.tuner_formats);
+       trace_eeprom("audio_processor=%d",tvdata.audio_processor);
+       trace_eeprom("model=%d",tvdata.model);
+       trace_eeprom("revision=%d",tvdata.revision);
+       trace_eeprom("serial_number=%d",tvdata.serial_number);
+       trace_eeprom("rev_str=%s",tvdata.rev_str);
+       hdw->tuner_type = tvdata.tuner_type;
+       hdw->serial_number = tvdata.serial_number;
+       hdw->std_mask_eeprom = tvdata.tuner_formats;
+
+       kfree(eeprom);
+
+       return 0;
+}
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.h b/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
new file mode 100644 (file)
index 0000000..8424297
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_EEPROM_H
+#define __PVRUSB2_EEPROM_H
+
+struct pvr2_hdw;
+
+int pvr2_eeprom_analyze(struct pvr2_hdw *);
+
+#endif /* __PVRUSB2_EEPROM_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
new file mode 100644 (file)
index 0000000..2cc3169
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/device.h>   // for linux/firmware.h
+#include <linux/firmware.h>
+#include "pvrusb2-util.h"
+#include "pvrusb2-encoder.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+
+
+
+/* Firmware mailbox flags - definitions found from ivtv */
+#define IVTV_MBOX_FIRMWARE_DONE 0x00000004
+#define IVTV_MBOX_DRIVER_DONE 0x00000002
+#define IVTV_MBOX_DRIVER_BUSY 0x00000001
+
+
+static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
+                                   const u32 *data, unsigned int dlen)
+{
+       unsigned int idx;
+       int ret;
+       unsigned int offs = 0;
+       unsigned int chunkCnt;
+
+       /*
+
+       Format: First byte must be 0x01.  Remaining 32 bit words are
+       spread out into chunks of 7 bytes each, little-endian ordered,
+       offset at zero within each 2 blank bytes following and a
+       single byte that is 0x44 plus the offset of the word.  Repeat
+       request for additional words, with offset adjusted
+       accordingly.
+
+       */
+       while (dlen) {
+               chunkCnt = 8;
+               if (chunkCnt > dlen) chunkCnt = dlen;
+               memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
+               hdw->cmd_buffer[0] = 0x01;
+               for (idx = 0; idx < chunkCnt; idx++) {
+                       hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
+                       PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
+                                         data[idx]);
+               }
+               ret = pvr2_send_request(hdw,
+                                       hdw->cmd_buffer,1+(chunkCnt*7),
+                                       0,0);
+               if (ret) return ret;
+               data += chunkCnt;
+               dlen -= chunkCnt;
+               offs += chunkCnt;
+       }
+
+       return 0;
+}
+
+
+static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
+                                  u32 *data, unsigned int dlen)
+{
+       unsigned int idx;
+       int ret;
+       unsigned int offs = 0;
+       unsigned int chunkCnt;
+
+       /*
+
+       Format: First byte must be 0x02 (status check) or 0x28 (read
+       back block of 32 bit words).  Next 6 bytes must be zero,
+       followed by a single byte of 0x44+offset for portion to be
+       read.  Returned data is packed set of 32 bits words that were
+       read.
+
+       */
+
+       while (dlen) {
+               chunkCnt = 16;
+               if (chunkCnt > dlen) chunkCnt = dlen;
+               memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
+               hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
+               hdw->cmd_buffer[7] = 0x44 + offs;
+               ret = pvr2_send_request(hdw,
+                                       hdw->cmd_buffer,8,
+                                       hdw->cmd_buffer,chunkCnt * 4);
+               if (ret) return ret;
+
+               for (idx = 0; idx < chunkCnt; idx++) {
+                       data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4);
+               }
+               data += chunkCnt;
+               dlen -= chunkCnt;
+               offs += chunkCnt;
+       }
+
+       return 0;
+}
+
+
+/* This prototype is set up to be compatible with the
+   cx2341x_mbox_func prototype in cx2341x.h, which should be in
+   kernels 2.6.18 or later.  We do this so that we can enable
+   cx2341x.ko to write to our encoder (by handing it a pointer to this
+   function).  For earlier kernels this doesn't really matter. */
+static int pvr2_encoder_cmd(void *ctxt,
+                           int cmd,
+                           int arg_cnt_send,
+                           int arg_cnt_recv,
+                           u32 *argp)
+{
+       unsigned int poll_count;
+       int ret = 0;
+       unsigned int idx;
+       /* These sizes look to be limited by the FX2 firmware implementation */
+       u32 wrData[16];
+       u32 rdData[16];
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;
+
+
+       /*
+
+       The encoder seems to speak entirely using blocks 32 bit words.
+       In ivtv driver terms, this is a mailbox which we populate with
+       data and watch what the hardware does with it.  The first word
+       is a set of flags used to control the transaction, the second
+       word is the command to execute, the third byte is zero (ivtv
+       driver suggests that this is some kind of return value), and
+       the fourth byte is a specified timeout (windows driver always
+       uses 0x00060000 except for one case when it is zero).  All
+       successive words are the argument words for the command.
+
+       First, write out the entire set of words, with the first word
+       being zero.
+
+       Next, write out just the first word again, but set it to
+       IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
+       probably means "go").
+
+       Next, read back 16 words as status.  Check the first word,
+       which should have IVTV_MBOX_FIRMWARE_DONE set.  If however
+       that bit is not set, then the command isn't done so repeat the
+       read.
+
+       Next, read back 32 words and compare with the original
+       arugments.  Hopefully they will match.
+
+       Finally, write out just the first word again, but set it to
+       0x0 this time (which probably means "idle").
+
+       */
+
+       if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Failed to write cx23416 command"
+                       " - too many input arguments"
+                       " (was given %u limit %u)",
+                       arg_cnt_send,
+                       (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
+               return -EINVAL;
+       }
+
+       if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Failed to write cx23416 command"
+                       " - too many return arguments"
+                       " (was given %u limit %u)",
+                       arg_cnt_recv,
+                       (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
+               return -EINVAL;
+       }
+
+
+       LOCK_TAKE(hdw->ctl_lock); do {
+
+               wrData[0] = 0;
+               wrData[1] = cmd;
+               wrData[2] = 0;
+               wrData[3] = 0x00060000;
+               for (idx = 0; idx < arg_cnt_send; idx++) {
+                       wrData[idx+4] = argp[idx];
+               }
+               for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
+                       wrData[idx+4] = 0;
+               }
+
+               ret = pvr2_encoder_write_words(hdw,wrData,idx);
+               if (ret) break;
+               wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
+               ret = pvr2_encoder_write_words(hdw,wrData,1);
+               if (ret) break;
+               poll_count = 0;
+               while (1) {
+                       if (poll_count < 10000000) poll_count++;
+                       ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
+                       if (ret) break;
+                       if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
+                               break;
+                       }
+                       if (poll_count == 100) {
+                               pvr2_trace(
+                                       PVR2_TRACE_ERROR_LEGS,
+                                       "***WARNING*** device's encoder"
+                                       " appears to be stuck"
+                                       " (status=0%08x)",rdData[0]);
+                               pvr2_trace(
+                                       PVR2_TRACE_ERROR_LEGS,
+                                       "Encoder command: 0x%02x",cmd);
+                               for (idx = 4; idx < arg_cnt_send; idx++) {
+                                       pvr2_trace(
+                                               PVR2_TRACE_ERROR_LEGS,
+                                               "Encoder arg%d: 0x%08x",
+                                               idx-3,wrData[idx]);
+                               }
+                               pvr2_trace(
+                                       PVR2_TRACE_ERROR_LEGS,
+                                       "Giving up waiting."
+                                       "  It is likely that"
+                                       " this is a bad idea...");
+                               ret = -EBUSY;
+                               break;
+                       }
+               }
+               if (ret) break;
+               wrData[0] = 0x7;
+               ret = pvr2_encoder_read_words(
+                       hdw,0,rdData,
+                       sizeof(rdData)/sizeof(rdData[0]));
+               if (ret) break;
+               for (idx = 0; idx < arg_cnt_recv; idx++) {
+                       argp[idx] = rdData[idx+4];
+               }
+
+               wrData[0] = 0x0;
+               ret = pvr2_encoder_write_words(hdw,wrData,1);
+               if (ret) break;
+
+       } while(0); LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+
+static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
+                            int args, ...)
+{
+       va_list vl;
+       unsigned int idx;
+       u32 data[12];
+
+       if (args > sizeof(data)/sizeof(data[0])) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Failed to write cx23416 command"
+                       " - too many arguments"
+                       " (was given %u limit %u)",
+                       args,(unsigned int)(sizeof(data)/sizeof(data[0])));
+               return -EINVAL;
+       }
+
+       va_start(vl, args);
+       for (idx = 0; idx < args; idx++) {
+               data[idx] = va_arg(vl, u32);
+       }
+       va_end(vl);
+
+       return pvr2_encoder_cmd(hdw,cmd,args,0,data);
+}
+
+int pvr2_encoder_configure(struct pvr2_hdw *hdw)
+{
+       int ret;
+       pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure"
+                  " (cx2341x module)");
+       hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING;
+       hdw->enc_ctl_state.width = hdw->res_hor_val;
+       hdw->enc_ctl_state.height = hdw->res_ver_val;
+       hdw->enc_ctl_state.is_50hz = ((hdw->std_mask_cur &
+                                      (V4L2_STD_NTSC|V4L2_STD_PAL_M)) ?
+                                     0 : 1);
+
+       ret = 0;
+
+       if (!ret) ret = pvr2_encoder_vcmd(
+               hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
+               0xf0, 0xf0);
+
+       /* setup firmware to notify us about some events (don't know why...) */
+       if (!ret) ret = pvr2_encoder_vcmd(
+               hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
+               0, 0, 0x10000000, 0xffffffff);
+
+       if (!ret) ret = pvr2_encoder_vcmd(
+               hdw,CX2341X_ENC_SET_VBI_LINE, 5,
+               0xffffffff,0,0,0,0);
+
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to configure cx32416");
+               return ret;
+       }
+
+       ret = cx2341x_update(hdw,pvr2_encoder_cmd,
+                            (hdw->enc_cur_valid ? &hdw->enc_cur_state : 0),
+                            &hdw->enc_ctl_state);
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Error from cx2341x module code=%d",ret);
+               return ret;
+       }
+
+       ret = 0;
+
+       if (!ret) ret = pvr2_encoder_vcmd(
+               hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
+
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to initialize cx32416 video input");
+               return ret;
+       }
+
+       hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+       memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
+              sizeof(struct cx2341x_mpeg_params));
+       hdw->enc_cur_valid = !0;
+       return 0;
+}
+
+
+int pvr2_encoder_start(struct pvr2_hdw *hdw)
+{
+       int status;
+
+       /* unmask some interrupts */
+       pvr2_write_register(hdw, 0x0048, 0xbfffffff);
+
+       /* change some GPIO data */
+       pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
+       pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
+
+       if (hdw->config == pvr2_config_vbi) {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+                                          0x01,0x14);
+       } else if (hdw->config == pvr2_config_mpeg) {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+                                          0,0x13);
+       } else {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+                                          0,0x13);
+       }
+       if (!status) {
+               hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+       }
+       return status;
+}
+
+int pvr2_encoder_stop(struct pvr2_hdw *hdw)
+{
+       int status;
+
+       /* mask all interrupts */
+       pvr2_write_register(hdw, 0x0048, 0xffffffff);
+
+       if (hdw->config == pvr2_config_vbi) {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+                                          0x01,0x01,0x14);
+       } else if (hdw->config == pvr2_config_mpeg) {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+                                          0x01,0,0x13);
+       } else {
+               status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+                                          0x01,0,0x13);
+       }
+
+       /* change some GPIO data */
+       /* Note: Bit d7 of dir appears to control the LED.  So we shut it
+          off here. */
+       pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
+       pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
+
+       if (!status) {
+               hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
+       }
+       return status;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
new file mode 100644 (file)
index 0000000..01b5a0b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_ENCODER_H
+#define __PVRUSB2_ENCODER_H
+
+struct pvr2_hdw;
+
+int pvr2_encoder_configure(struct pvr2_hdw *);
+int pvr2_encoder_start(struct pvr2_hdw *);
+int pvr2_encoder_stop(struct pvr2_hdw *);
+
+#endif /* __PVRUSB2_ENCODER_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
new file mode 100644 (file)
index 0000000..ba2afbf
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_HDW_INTERNAL_H
+#define __PVRUSB2_HDW_INTERNAL_H
+
+/*
+
+  This header sets up all the internal structures and definitions needed to
+  track and coordinate the driver's interaction with the hardware.  ONLY
+  source files which actually implement part of that whole circus should be
+  including this header.  Higher levels, like the external layers to the
+  various public APIs (V4L, sysfs, etc) should NOT ever include this
+  private, internal header.  This means that pvrusb2-hdw, pvrusb2-encoder,
+  etc will include this, but pvrusb2-v4l should not.
+
+*/
+
+#include <linux/config.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-io.h"
+#include <media/cx2341x.h>
+
+/* Legal values for the SRATE state variable */
+#define PVR2_CVAL_SRATE_48 0
+#define PVR2_CVAL_SRATE_44_1 1
+
+/* Legal values for the AUDIOBITRATE state variable */
+#define PVR2_CVAL_AUDIOBITRATE_384 0
+#define PVR2_CVAL_AUDIOBITRATE_320 1
+#define PVR2_CVAL_AUDIOBITRATE_256 2
+#define PVR2_CVAL_AUDIOBITRATE_224 3
+#define PVR2_CVAL_AUDIOBITRATE_192 4
+#define PVR2_CVAL_AUDIOBITRATE_160 5
+#define PVR2_CVAL_AUDIOBITRATE_128 6
+#define PVR2_CVAL_AUDIOBITRATE_112 7
+#define PVR2_CVAL_AUDIOBITRATE_96 8
+#define PVR2_CVAL_AUDIOBITRATE_80 9
+#define PVR2_CVAL_AUDIOBITRATE_64 10
+#define PVR2_CVAL_AUDIOBITRATE_56 11
+#define PVR2_CVAL_AUDIOBITRATE_48 12
+#define PVR2_CVAL_AUDIOBITRATE_32 13
+#define PVR2_CVAL_AUDIOBITRATE_VBR 14
+
+/* Legal values for the AUDIOEMPHASIS state variable */
+#define PVR2_CVAL_AUDIOEMPHASIS_NONE 0
+#define PVR2_CVAL_AUDIOEMPHASIS_50_15 1
+#define PVR2_CVAL_AUDIOEMPHASIS_CCITT 2
+
+/* Legal values for PVR2_CID_HSM */
+#define PVR2_CVAL_HSM_FAIL 0
+#define PVR2_CVAL_HSM_FULL 1
+#define PVR2_CVAL_HSM_HIGH 2
+
+#define PVR2_VID_ENDPOINT        0x84
+#define PVR2_UNK_ENDPOINT        0x86    /* maybe raw yuv ? */
+#define PVR2_VBI_ENDPOINT        0x88
+
+#define PVR2_CTL_BUFFSIZE        64
+
+#define FREQTABLE_SIZE 500
+
+#define LOCK_TAKE(x) do { mutex_lock(&x##_mutex); x##_held = !0; } while (0)
+#define LOCK_GIVE(x) do { x##_held = 0; mutex_unlock(&x##_mutex); } while (0)
+
+struct pvr2_decoder;
+
+typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
+typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
+typedef int (*pvr2_ctlf_get_value)(struct pvr2_ctrl *,int *);
+typedef int (*pvr2_ctlf_set_value)(struct pvr2_ctrl *,int msk,int val);
+typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val,
+                                   char *,unsigned int,unsigned int *);
+typedef int (*pvr2_ctlf_sym_to_val)(struct pvr2_ctrl *,
+                                   const char *,unsigned int,
+                                   int *mskp,int *valp);
+typedef unsigned int (*pvr2_ctlf_get_v4lflags)(struct pvr2_ctrl *);
+
+/* This structure describes a specific control.  A table of these is set up
+   in pvrusb2-hdw.c. */
+struct pvr2_ctl_info {
+       /* Control's name suitable for use as an identifier */
+       const char *name;
+
+       /* Short description of control */
+       const char *desc;
+
+       /* Control's implementation */
+       pvr2_ctlf_get_value get_value;      /* Get its value */
+       pvr2_ctlf_set_value set_value;      /* Set its value */
+       pvr2_ctlf_val_to_sym val_to_sym;    /* Custom convert value->symbol */
+       pvr2_ctlf_sym_to_val sym_to_val;    /* Custom convert symbol->value */
+       pvr2_ctlf_is_dirty is_dirty;        /* Return true if dirty */
+       pvr2_ctlf_clear_dirty clear_dirty;  /* Clear dirty state */
+       pvr2_ctlf_get_v4lflags get_v4lflags;/* Retrieve v4l flags */
+
+       /* Control's type (int, enum, bitmask) */
+       enum pvr2_ctl_type type;
+
+       /* Associated V4L control ID, if any */
+       int v4l_id;
+
+       /* Associated driver internal ID, if any */
+       int internal_id;
+
+       /* Don't implicitly initialize this control's value */
+       int skip_init;
+
+       /* Starting value for this control */
+       int default_value;
+
+       /* Type-specific control information */
+       union {
+               struct { /* Integer control */
+                       long min_value; /* lower limit */
+                       long max_value; /* upper limit */
+               } type_int;
+               struct { /* enumerated control */
+                       unsigned int count;       /* enum value count */
+                       const char **value_names; /* symbol names */
+               } type_enum;
+               struct { /* bitmask control */
+                       unsigned int valid_bits; /* bits in use */
+                       const char **bit_names;  /* symbol name/bit */
+               } type_bitmask;
+       } def;
+};
+
+
+/* Same as pvr2_ctl_info, but includes storage for the control description */
+#define PVR2_CTLD_INFO_DESC_SIZE 32
+struct pvr2_ctld_info {
+       struct pvr2_ctl_info info;
+       char desc[PVR2_CTLD_INFO_DESC_SIZE];
+};
+
+struct pvr2_ctrl {
+       const struct pvr2_ctl_info *info;
+       struct pvr2_hdw *hdw;
+};
+
+
+struct pvr2_audio_stat {
+       void *ctxt;
+       void (*detach)(void *);
+       int (*status)(void *);
+};
+
+struct pvr2_decoder_ctrl {
+       void *ctxt;
+       void (*detach)(void *);
+       void (*enable)(void *,int);
+       int (*tuned)(void *);
+       void (*force_reset)(void *);
+};
+
+#define PVR2_I2C_PEND_DETECT  0x01  /* Need to detect a client type */
+#define PVR2_I2C_PEND_CLIENT  0x02  /* Client needs a specific update */
+#define PVR2_I2C_PEND_REFRESH 0x04  /* Client has specific pending bits */
+#define PVR2_I2C_PEND_STALE   0x08  /* Broadcast pending bits */
+
+#define PVR2_I2C_PEND_ALL (PVR2_I2C_PEND_DETECT |\
+                          PVR2_I2C_PEND_CLIENT |\
+                          PVR2_I2C_PEND_REFRESH |\
+                          PVR2_I2C_PEND_STALE)
+
+/* Disposition of firmware1 loading situation */
+#define FW1_STATE_UNKNOWN 0
+#define FW1_STATE_MISSING 1
+#define FW1_STATE_FAILED 2
+#define FW1_STATE_RELOAD 3
+#define FW1_STATE_OK 4
+
+/* Known major hardware variants, keyed from device ID */
+#define PVR2_HDW_TYPE_29XXX 0
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+#define PVR2_HDW_TYPE_24XXX 1
+#endif
+
+typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
+#define PVR2_I2C_FUNC_CNT 128
+
+/* This structure contains all state data directly needed to
+   manipulate the hardware (as opposed to complying with a kernel
+   interface) */
+struct pvr2_hdw {
+       /* Underlying USB device handle */
+       struct usb_device *usb_dev;
+       struct usb_interface *usb_intf;
+
+       /* Device type, one of PVR2_HDW_TYPE_xxxxx */
+       unsigned int hdw_type;
+
+       /* Video spigot */
+       struct pvr2_stream *vid_stream;
+
+       /* Mutex for all hardware state control */
+       struct mutex big_lock_mutex;
+       int big_lock_held;  /* For debugging */
+
+       void (*poll_trigger_func)(void *);
+       void *poll_trigger_data;
+
+       char name[32];
+
+       /* I2C stuff */
+       struct i2c_adapter i2c_adap;
+       struct i2c_algorithm i2c_algo;
+       pvr2_i2c_func i2c_func[PVR2_I2C_FUNC_CNT];
+       int i2c_cx25840_hack_state;
+       int i2c_linked;
+       unsigned int i2c_pend_types;    /* Which types of update are needed */
+       unsigned long i2c_pend_mask;    /* Change bits we need to scan */
+       unsigned long i2c_stale_mask;   /* Pending broadcast change bits */
+       unsigned long i2c_active_mask;  /* All change bits currently in use */
+       struct list_head i2c_clients;
+       struct mutex i2c_list_lock;
+
+       /* Frequency table */
+       unsigned int freqTable[FREQTABLE_SIZE];
+       unsigned int freqProgSlot;
+       unsigned int freqSlot;
+
+       /* Stuff for handling low level control interaction with device */
+       struct mutex ctl_lock_mutex;
+       int ctl_lock_held;  /* For debugging */
+       struct urb *ctl_write_urb;
+       struct urb *ctl_read_urb;
+       unsigned char *ctl_write_buffer;
+       unsigned char *ctl_read_buffer;
+       volatile int ctl_write_pend_flag;
+       volatile int ctl_read_pend_flag;
+       volatile int ctl_timeout_flag;
+       struct completion ctl_done;
+       unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE];
+       int cmd_debug_state;               // Low level command debugging info
+       unsigned char cmd_debug_code;      //
+       unsigned int cmd_debug_write_len;  //
+       unsigned int cmd_debug_read_len;   //
+
+       int flag_ok;            // device in known good state
+       int flag_disconnected;  // flag_ok == 0 due to disconnect
+       int flag_init_ok;       // true if structure is fully initialized
+       int flag_streaming_enabled; // true if streaming should be on
+       int fw1_state;          // current situation with fw1
+
+       int flag_decoder_is_tuned;
+
+       struct pvr2_decoder_ctrl *decoder_ctrl;
+
+       // CPU firmware info (used to help find / save firmware data)
+       char *fw_buffer;
+       unsigned int fw_size;
+
+       // Which subsystem pieces have been enabled / configured
+       unsigned long subsys_enabled_mask;
+
+       // Which subsystems are manipulated to enable streaming
+       unsigned long subsys_stream_mask;
+
+       // True if there is a request to trigger logging of state in each
+       // module.
+       int log_requested;
+
+       /* Tuner / frequency control stuff */
+       unsigned int tuner_type;
+       int tuner_updated;
+       unsigned int freqVal;
+       int freqDirty;
+
+       /* Video standard handling */
+       v4l2_std_id std_mask_eeprom; // Hardware supported selections
+       v4l2_std_id std_mask_avail;  // Which standards we may select from
+       v4l2_std_id std_mask_cur;    // Currently selected standard(s)
+       unsigned int std_enum_cnt;   // # of enumerated standards
+       int std_enum_cur;            // selected standard enumeration value
+       int std_dirty;               // True if std_mask_cur has changed
+       struct pvr2_ctl_info std_info_enum;
+       struct pvr2_ctl_info std_info_avail;
+       struct pvr2_ctl_info std_info_cur;
+       struct v4l2_standard *std_defs;
+       const char **std_enum_names;
+
+       // Generated string names, one per actual V4L2 standard
+       const char *std_mask_ptrs[32];
+       char std_mask_names[32][10];
+
+       int unit_number;             /* ID for driver instance */
+       unsigned long serial_number; /* ID for hardware itself */
+
+       /* Minor number used by v4l logic (yes, this is a hack, as there should
+          be no v4l junk here).  Probably a better way to do this. */
+       int v4l_minor_number;
+
+       /* Location of eeprom or a negative number if none */
+       int eeprom_addr;
+
+       enum pvr2_config config;
+
+       /* Information about what audio signal we're hearing */
+       int flag_stereo;
+       int flag_bilingual;
+       struct pvr2_audio_stat *audio_stat;
+
+       /* Control state needed for cx2341x module */
+       struct cx2341x_mpeg_params enc_cur_state;
+       struct cx2341x_mpeg_params enc_ctl_state;
+       /* True if an encoder attribute has changed */
+       int enc_stale;
+       /* True if enc_cur_state is valid */
+       int enc_cur_valid;
+
+       /* Control state */
+#define VCREATE_DATA(lab) int lab##_val; int lab##_dirty
+       VCREATE_DATA(brightness);
+       VCREATE_DATA(contrast);
+       VCREATE_DATA(saturation);
+       VCREATE_DATA(hue);
+       VCREATE_DATA(volume);
+       VCREATE_DATA(balance);
+       VCREATE_DATA(bass);
+       VCREATE_DATA(treble);
+       VCREATE_DATA(mute);
+       VCREATE_DATA(input);
+       VCREATE_DATA(audiomode);
+       VCREATE_DATA(res_hor);
+       VCREATE_DATA(res_ver);
+       VCREATE_DATA(srate);
+#undef VCREATE_DATA
+
+       struct pvr2_ctld_info *mpeg_ctrl_info;
+
+       struct pvr2_ctrl *controls;
+       unsigned int control_cnt;
+};
+
+int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
+
+unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *);
+
+void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
+                                    unsigned long msk,unsigned long val);
+void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
+                                           unsigned long msk,
+                                           unsigned long val);
+
+void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
+void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
+
+int pvr2_i2c_basic_op(struct pvr2_hdw *,u8 i2c_addr,
+                     u8 *wdata,u16 wlen,
+                     u8 *rdata,u16 rlen);
+
+#endif /* __PVRUSB2_HDW_INTERNAL_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
new file mode 100644 (file)
index 0000000..643c471
--- /dev/null
@@ -0,0 +1,3120 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/videodev2.h>
+#include <asm/semaphore.h>
+#include "pvrusb2.h"
+#include "pvrusb2-std.h"
+#include "pvrusb2-util.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-tuner.h"
+#include "pvrusb2-eeprom.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-encoder.h"
+#include "pvrusb2-debug.h"
+
+struct usb_device_id pvr2_device_table[] = {
+       [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
+#endif
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, pvr2_device_table);
+
+static const char *pvr2_device_names[] = {
+       [PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       [PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
+#endif
+};
+
+struct pvr2_string_table {
+       const char **lst;
+       unsigned int cnt;
+};
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+// Names of other client modules to request for 24xxx model hardware
+static const char *pvr2_client_24xxx[] = {
+       "cx25840",
+       "tuner",
+       "tda9887",
+       "wm8775",
+};
+#endif
+
+// Names of other client modules to request for 29xxx model hardware
+static const char *pvr2_client_29xxx[] = {
+       "msp3400",
+       "saa7115",
+       "tuner",
+       "tda9887",
+};
+
+static struct pvr2_string_table pvr2_client_lists[] = {
+       [PVR2_HDW_TYPE_29XXX] = {
+               pvr2_client_29xxx,
+               sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+       },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       [PVR2_HDW_TYPE_24XXX] = {
+               pvr2_client_24xxx,
+               sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+       },
+#endif
+};
+
+static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = 0};
+DECLARE_MUTEX(pvr2_unit_sem);
+
+static int ctlchg = 0;
+static int initusbreset = 1;
+static int procreload = 0;
+static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
+static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
+static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
+static int init_pause_msec = 0;
+
+module_param(ctlchg, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value");
+module_param(init_pause_msec, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay");
+module_param(initusbreset, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe");
+module_param(procreload, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(procreload,
+                "Attempt init failure recovery with firmware reload");
+module_param_array(tuner,    int, NULL, 0444);
+MODULE_PARM_DESC(tuner,"specify installed tuner type");
+module_param_array(video_std,    int, NULL, 0444);
+MODULE_PARM_DESC(video_std,"specify initial video standard");
+module_param_array(tolerance,    int, NULL, 0444);
+MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
+
+#define PVR2_CTL_WRITE_ENDPOINT  0x01
+#define PVR2_CTL_READ_ENDPOINT   0x81
+
+#define PVR2_GPIO_IN 0x9008
+#define PVR2_GPIO_OUT 0x900c
+#define PVR2_GPIO_DIR 0x9020
+
+#define trace_firmware(...) pvr2_trace(PVR2_TRACE_FIRMWARE,__VA_ARGS__)
+
+#define PVR2_FIRMWARE_ENDPOINT   0x02
+
+/* size of a firmware chunk */
+#define FIRMWARE_CHUNK_SIZE 0x2000
+
+/* Define the list of additional controls we'll dynamically construct based
+   on query of the cx2341x module. */
+struct pvr2_mpeg_ids {
+       const char *strid;
+       int id;
+};
+static const struct pvr2_mpeg_ids mpeg_ids[] = {
+       {
+               .strid = "audio_layer",
+               .id = V4L2_CID_MPEG_AUDIO_ENCODING,
+       },{
+               .strid = "audio_bitrate",
+               .id = V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+       },{
+               /* Already using audio_mode elsewhere :-( */
+               .strid = "mpeg_audio_mode",
+               .id = V4L2_CID_MPEG_AUDIO_MODE,
+       },{
+               .strid = "mpeg_audio_mode_extension",
+               .id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+       },{
+               .strid = "audio_emphasis",
+               .id = V4L2_CID_MPEG_AUDIO_EMPHASIS,
+       },{
+               .strid = "audio_crc",
+               .id = V4L2_CID_MPEG_AUDIO_CRC,
+       },{
+               .strid = "video_aspect",
+               .id = V4L2_CID_MPEG_VIDEO_ASPECT,
+       },{
+               .strid = "video_b_frames",
+               .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
+       },{
+               .strid = "video_gop_size",
+               .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+       },{
+               .strid = "video_gop_closure",
+               .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+       },{
+               .strid = "video_pulldown",
+               .id = V4L2_CID_MPEG_VIDEO_PULLDOWN,
+       },{
+               .strid = "video_bitrate_mode",
+               .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+       },{
+               .strid = "video_bitrate",
+               .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+       },{
+               .strid = "video_bitrate_peak",
+               .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+       },{
+               .strid = "video_temporal_decimation",
+               .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+       },{
+               .strid = "stream_type",
+               .id = V4L2_CID_MPEG_STREAM_TYPE,
+       },{
+               .strid = "video_spatial_filter_mode",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+       },{
+               .strid = "video_spatial_filter",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+       },{
+               .strid = "video_luma_spatial_filter_type",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+       },{
+               .strid = "video_chroma_spatial_filter_type",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+       },{
+               .strid = "video_temporal_filter_mode",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+       },{
+               .strid = "video_temporal_filter",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+       },{
+               .strid = "video_median_filter_type",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+       },{
+               .strid = "video_luma_median_filter_top",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+       },{
+               .strid = "video_luma_median_filter_bottom",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+       },{
+               .strid = "video_chroma_median_filter_top",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+       },{
+               .strid = "video_chroma_median_filter_bottom",
+               .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+       }
+};
+#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+
+static const char *control_values_srate[] = {
+       [PVR2_CVAL_SRATE_48]   = "48KHz",
+       [PVR2_CVAL_SRATE_44_1] = "44.1KHz",
+};
+
+
+
+
+static const char *control_values_input[] = {
+       [PVR2_CVAL_INPUT_TV]        = "television",  /*xawtv needs this name*/
+       [PVR2_CVAL_INPUT_RADIO]     = "radio",
+       [PVR2_CVAL_INPUT_SVIDEO]    = "s-video",
+       [PVR2_CVAL_INPUT_COMPOSITE] = "composite",
+};
+
+
+static const char *control_values_audiomode[] = {
+       [V4L2_TUNER_MODE_MONO]   = "Mono",
+       [V4L2_TUNER_MODE_STEREO] = "Stereo",
+       [V4L2_TUNER_MODE_LANG1]  = "Lang1",
+       [V4L2_TUNER_MODE_LANG2]  = "Lang2",
+       [V4L2_TUNER_MODE_LANG1_LANG2] = "Lang1+Lang2",
+};
+
+
+static const char *control_values_hsm[] = {
+       [PVR2_CVAL_HSM_FAIL] = "Fail",
+       [PVR2_CVAL_HSM_HIGH] = "High",
+       [PVR2_CVAL_HSM_FULL] = "Full",
+};
+
+
+static const char *control_values_subsystem[] = {
+       [PVR2_SUBSYS_B_ENC_FIRMWARE]  = "enc_firmware",
+       [PVR2_SUBSYS_B_ENC_CFG] = "enc_config",
+       [PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run",
+       [PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run",
+       [PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
+};
+
+
+static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
+               *vp = hdw->freqTable[hdw->freqProgSlot-1];
+       } else {
+               *vp = 0;
+       }
+       return 0;
+}
+
+static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
+               hdw->freqTable[hdw->freqProgSlot-1] = v;
+       }
+       return 0;
+}
+
+static int ctrl_channelprog_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->freqProgSlot;
+       return 0;
+}
+
+static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if ((v >= 0) && (v <= FREQTABLE_SIZE)) {
+               hdw->freqProgSlot = v;
+       }
+       return 0;
+}
+
+static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->freqSlot;
+       return 0;
+}
+
+static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       unsigned freq = 0;
+       struct pvr2_hdw *hdw = cptr->hdw;
+       hdw->freqSlot = v;
+       if ((hdw->freqSlot > 0) && (hdw->freqSlot <= FREQTABLE_SIZE)) {
+               freq = hdw->freqTable[hdw->freqSlot-1];
+       }
+       if (freq && (freq != hdw->freqVal)) {
+               hdw->freqVal = freq;
+               hdw->freqDirty = !0;
+       }
+       return 0;
+}
+
+static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->freqVal;
+       return 0;
+}
+
+static int ctrl_freq_is_dirty(struct pvr2_ctrl *cptr)
+{
+       return cptr->hdw->freqDirty != 0;
+}
+
+static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
+{
+       cptr->hdw->freqDirty = 0;
+}
+
+static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       hdw->freqVal = v;
+       hdw->freqDirty = !0;
+       hdw->freqSlot = 0;
+       return 0;
+}
+
+static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
+{
+       return cptr->hdw->enc_stale != 0;
+}
+
+static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr)
+{
+       cptr->hdw->enc_stale = 0;
+}
+
+static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       int ret;
+       struct v4l2_ext_controls cs;
+       struct v4l2_ext_control c1;
+       memset(&cs,0,sizeof(cs));
+       memset(&c1,0,sizeof(c1));
+       cs.controls = &c1;
+       cs.count = 1;
+       c1.id = cptr->info->v4l_id;
+       ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+                               VIDIOC_G_EXT_CTRLS);
+       if (ret) return ret;
+       *vp = c1.value;
+       return 0;
+}
+
+static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       int ret;
+       struct v4l2_ext_controls cs;
+       struct v4l2_ext_control c1;
+       memset(&cs,0,sizeof(cs));
+       memset(&c1,0,sizeof(c1));
+       cs.controls = &c1;
+       cs.count = 1;
+       c1.id = cptr->info->v4l_id;
+       c1.value = v;
+       ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+                               VIDIOC_S_EXT_CTRLS);
+       if (ret) return ret;
+       cptr->hdw->enc_stale = !0;
+       return 0;
+}
+
+static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr)
+{
+       struct v4l2_queryctrl qctrl;
+       struct pvr2_ctl_info *info;
+       qctrl.id = cptr->info->v4l_id;
+       cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl);
+       /* Strip out the const so we can adjust a function pointer.  It's
+          OK to do this here because we know this is a dynamically created
+          control, so the underlying storage for the info pointer is (a)
+          private to us, and (b) not in read-only storage.  Either we do
+          this or we significantly complicate the underlying control
+          implementation. */
+       info = (struct pvr2_ctl_info *)(cptr->info);
+       if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
+               if (info->set_value) {
+                       info->set_value = 0;
+               }
+       } else {
+               if (!(info->set_value)) {
+                       info->set_value = ctrl_cx2341x_set;
+               }
+       }
+       return qctrl.flags;
+}
+
+static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->flag_streaming_enabled;
+       return 0;
+}
+
+static int ctrl_hsm_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       int result = pvr2_hdw_is_hsm(cptr->hdw);
+       *vp = PVR2_CVAL_HSM_FULL;
+       if (result < 0) *vp = PVR2_CVAL_HSM_FAIL;
+       if (result) *vp = PVR2_CVAL_HSM_HIGH;
+       return 0;
+}
+
+static int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->std_mask_avail;
+       return 0;
+}
+
+static int ctrl_stdavail_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       v4l2_std_id ns;
+       ns = hdw->std_mask_avail;
+       ns = (ns & ~m) | (v & m);
+       if (ns == hdw->std_mask_avail) return 0;
+       hdw->std_mask_avail = ns;
+       pvr2_hdw_internal_set_std_avail(hdw);
+       pvr2_hdw_internal_find_stdenum(hdw);
+       return 0;
+}
+
+static int ctrl_std_val_to_sym(struct pvr2_ctrl *cptr,int msk,int val,
+                              char *bufPtr,unsigned int bufSize,
+                              unsigned int *len)
+{
+       *len = pvr2_std_id_to_str(bufPtr,bufSize,msk & val);
+       return 0;
+}
+
+static int ctrl_std_sym_to_val(struct pvr2_ctrl *cptr,
+                              const char *bufPtr,unsigned int bufSize,
+                              int *mskp,int *valp)
+{
+       int ret;
+       v4l2_std_id id;
+       ret = pvr2_std_str_to_id(&id,bufPtr,bufSize);
+       if (ret < 0) return ret;
+       if (mskp) *mskp = id;
+       if (valp) *valp = id;
+       return 0;
+}
+
+static int ctrl_stdcur_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->std_mask_cur;
+       return 0;
+}
+
+static int ctrl_stdcur_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       v4l2_std_id ns;
+       ns = hdw->std_mask_cur;
+       ns = (ns & ~m) | (v & m);
+       if (ns == hdw->std_mask_cur) return 0;
+       hdw->std_mask_cur = ns;
+       hdw->std_dirty = !0;
+       pvr2_hdw_internal_find_stdenum(hdw);
+       return 0;
+}
+
+static int ctrl_stdcur_is_dirty(struct pvr2_ctrl *cptr)
+{
+       return cptr->hdw->std_dirty != 0;
+}
+
+static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
+{
+       cptr->hdw->std_dirty = 0;
+}
+
+static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
+               PVR2_SIGNAL_OK) ? 1 : 0);
+       return 0;
+}
+
+static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->subsys_enabled_mask;
+       return 0;
+}
+
+static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v);
+       return 0;
+}
+
+static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->subsys_stream_mask;
+       return 0;
+}
+
+static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v);
+       return 0;
+}
+
+static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if (v < 0) return -EINVAL;
+       if (v > hdw->std_enum_cnt) return -EINVAL;
+       hdw->std_enum_cur = v;
+       if (!v) return 0;
+       v--;
+       if (hdw->std_mask_cur == hdw->std_defs[v].id) return 0;
+       hdw->std_mask_cur = hdw->std_defs[v].id;
+       hdw->std_dirty = !0;
+       return 0;
+}
+
+
+static int ctrl_stdenumcur_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->std_enum_cur;
+       return 0;
+}
+
+
+static int ctrl_stdenumcur_is_dirty(struct pvr2_ctrl *cptr)
+{
+       return cptr->hdw->std_dirty != 0;
+}
+
+
+static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
+{
+       cptr->hdw->std_dirty = 0;
+}
+
+
+#define DEFINT(vmin,vmax) \
+       .type = pvr2_ctl_int, \
+       .def.type_int.min_value = vmin, \
+       .def.type_int.max_value = vmax
+
+#define DEFENUM(tab) \
+       .type = pvr2_ctl_enum, \
+       .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
+       .def.type_enum.value_names = tab
+
+#define DEFBOOL \
+       .type = pvr2_ctl_bool
+
+#define DEFMASK(msk,tab) \
+       .type = pvr2_ctl_bitmask, \
+       .def.type_bitmask.valid_bits = msk, \
+       .def.type_bitmask.bit_names = tab
+
+#define DEFREF(vname) \
+       .set_value = ctrl_set_##vname, \
+       .get_value = ctrl_get_##vname, \
+       .is_dirty = ctrl_isdirty_##vname, \
+       .clear_dirty = ctrl_cleardirty_##vname
+
+
+#define VCREATE_FUNCS(vname) \
+static int ctrl_get_##vname(struct pvr2_ctrl *cptr,int *vp) \
+{*vp = cptr->hdw->vname##_val; return 0;} \
+static int ctrl_set_##vname(struct pvr2_ctrl *cptr,int m,int v) \
+{cptr->hdw->vname##_val = v; cptr->hdw->vname##_dirty = !0; return 0;} \
+static int ctrl_isdirty_##vname(struct pvr2_ctrl *cptr) \
+{return cptr->hdw->vname##_dirty != 0;} \
+static void ctrl_cleardirty_##vname(struct pvr2_ctrl *cptr) \
+{cptr->hdw->vname##_dirty = 0;}
+
+VCREATE_FUNCS(brightness)
+VCREATE_FUNCS(contrast)
+VCREATE_FUNCS(saturation)
+VCREATE_FUNCS(hue)
+VCREATE_FUNCS(volume)
+VCREATE_FUNCS(balance)
+VCREATE_FUNCS(bass)
+VCREATE_FUNCS(treble)
+VCREATE_FUNCS(mute)
+VCREATE_FUNCS(input)
+VCREATE_FUNCS(audiomode)
+VCREATE_FUNCS(res_hor)
+VCREATE_FUNCS(res_ver)
+VCREATE_FUNCS(srate)
+
+#define MIN_FREQ 55250000L
+#define MAX_FREQ 850000000L
+
+/* Table definition of all controls which can be manipulated */
+static const struct pvr2_ctl_info control_defs[] = {
+       {
+               .v4l_id = V4L2_CID_BRIGHTNESS,
+               .desc = "Brightness",
+               .name = "brightness",
+               .default_value = 128,
+               DEFREF(brightness),
+               DEFINT(0,255),
+       },{
+               .v4l_id = V4L2_CID_CONTRAST,
+               .desc = "Contrast",
+               .name = "contrast",
+               .default_value = 68,
+               DEFREF(contrast),
+               DEFINT(0,127),
+       },{
+               .v4l_id = V4L2_CID_SATURATION,
+               .desc = "Saturation",
+               .name = "saturation",
+               .default_value = 64,
+               DEFREF(saturation),
+               DEFINT(0,127),
+       },{
+               .v4l_id = V4L2_CID_HUE,
+               .desc = "Hue",
+               .name = "hue",
+               .default_value = 0,
+               DEFREF(hue),
+               DEFINT(-128,127),
+       },{
+               .v4l_id = V4L2_CID_AUDIO_VOLUME,
+               .desc = "Volume",
+               .name = "volume",
+               .default_value = 65535,
+               DEFREF(volume),
+               DEFINT(0,65535),
+       },{
+               .v4l_id = V4L2_CID_AUDIO_BALANCE,
+               .desc = "Balance",
+               .name = "balance",
+               .default_value = 0,
+               DEFREF(balance),
+               DEFINT(-32768,32767),
+       },{
+               .v4l_id = V4L2_CID_AUDIO_BASS,
+               .desc = "Bass",
+               .name = "bass",
+               .default_value = 0,
+               DEFREF(bass),
+               DEFINT(-32768,32767),
+       },{
+               .v4l_id = V4L2_CID_AUDIO_TREBLE,
+               .desc = "Treble",
+               .name = "treble",
+               .default_value = 0,
+               DEFREF(treble),
+               DEFINT(-32768,32767),
+       },{
+               .v4l_id = V4L2_CID_AUDIO_MUTE,
+               .desc = "Mute",
+               .name = "mute",
+               .default_value = 0,
+               DEFREF(mute),
+               DEFBOOL,
+       },{
+               .desc = "Video Source",
+               .name = "input",
+               .internal_id = PVR2_CID_INPUT,
+               .default_value = PVR2_CVAL_INPUT_TV,
+               DEFREF(input),
+               DEFENUM(control_values_input),
+       },{
+               .desc = "Audio Mode",
+               .name = "audio_mode",
+               .internal_id = PVR2_CID_AUDIOMODE,
+               .default_value = V4L2_TUNER_MODE_STEREO,
+               DEFREF(audiomode),
+               DEFENUM(control_values_audiomode),
+       },{
+               .desc = "Horizontal capture resolution",
+               .name = "resolution_hor",
+               .internal_id = PVR2_CID_HRES,
+               .default_value = 720,
+               DEFREF(res_hor),
+               DEFINT(320,720),
+       },{
+               .desc = "Vertical capture resolution",
+               .name = "resolution_ver",
+               .internal_id = PVR2_CID_VRES,
+               .default_value = 480,
+               DEFREF(res_ver),
+               DEFINT(200,625),
+       },{
+               .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+               .desc = "Sample rate",
+               .name = "srate",
+               .default_value = PVR2_CVAL_SRATE_48,
+               DEFREF(srate),
+               DEFENUM(control_values_srate),
+       },{
+               .desc = "Tuner Frequency (Hz)",
+               .name = "frequency",
+               .internal_id = PVR2_CID_FREQUENCY,
+               .default_value = 175250000L,
+               .set_value = ctrl_freq_set,
+               .get_value = ctrl_freq_get,
+               .is_dirty = ctrl_freq_is_dirty,
+               .clear_dirty = ctrl_freq_clear_dirty,
+               DEFINT(MIN_FREQ,MAX_FREQ),
+       },{
+               .desc = "Channel",
+               .name = "channel",
+               .set_value = ctrl_channel_set,
+               .get_value = ctrl_channel_get,
+               DEFINT(0,FREQTABLE_SIZE),
+       },{
+               .desc = "Channel Program Frequency",
+               .name = "freq_table_value",
+               .set_value = ctrl_channelfreq_set,
+               .get_value = ctrl_channelfreq_get,
+               DEFINT(MIN_FREQ,MAX_FREQ),
+       },{
+               .desc = "Channel Program ID",
+               .name = "freq_table_channel",
+               .set_value = ctrl_channelprog_set,
+               .get_value = ctrl_channelprog_get,
+               DEFINT(0,FREQTABLE_SIZE),
+       },{
+               .desc = "Streaming Enabled",
+               .name = "streaming_enabled",
+               .get_value = ctrl_streamingenabled_get,
+               DEFBOOL,
+       },{
+               .desc = "USB Speed",
+               .name = "usb_speed",
+               .get_value = ctrl_hsm_get,
+               DEFENUM(control_values_hsm),
+       },{
+               .desc = "Signal Present",
+               .name = "signal_present",
+               .get_value = ctrl_signal_get,
+               DEFBOOL,
+       },{
+               .desc = "Video Standards Available Mask",
+               .name = "video_standard_mask_available",
+               .internal_id = PVR2_CID_STDAVAIL,
+               .skip_init = !0,
+               .get_value = ctrl_stdavail_get,
+               .set_value = ctrl_stdavail_set,
+               .val_to_sym = ctrl_std_val_to_sym,
+               .sym_to_val = ctrl_std_sym_to_val,
+               .type = pvr2_ctl_bitmask,
+       },{
+               .desc = "Video Standards In Use Mask",
+               .name = "video_standard_mask_active",
+               .internal_id = PVR2_CID_STDCUR,
+               .skip_init = !0,
+               .get_value = ctrl_stdcur_get,
+               .set_value = ctrl_stdcur_set,
+               .is_dirty = ctrl_stdcur_is_dirty,
+               .clear_dirty = ctrl_stdcur_clear_dirty,
+               .val_to_sym = ctrl_std_val_to_sym,
+               .sym_to_val = ctrl_std_sym_to_val,
+               .type = pvr2_ctl_bitmask,
+       },{
+               .desc = "Subsystem enabled mask",
+               .name = "debug_subsys_mask",
+               .skip_init = !0,
+               .get_value = ctrl_subsys_get,
+               .set_value = ctrl_subsys_set,
+               DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
+       },{
+               .desc = "Subsystem stream mask",
+               .name = "debug_subsys_stream_mask",
+               .skip_init = !0,
+               .get_value = ctrl_subsys_stream_get,
+               .set_value = ctrl_subsys_stream_set,
+               DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
+       },{
+               .desc = "Video Standard Name",
+               .name = "video_standard",
+               .internal_id = PVR2_CID_STDENUM,
+               .skip_init = !0,
+               .get_value = ctrl_stdenumcur_get,
+               .set_value = ctrl_stdenumcur_set,
+               .is_dirty = ctrl_stdenumcur_is_dirty,
+               .clear_dirty = ctrl_stdenumcur_clear_dirty,
+               .type = pvr2_ctl_enum,
+       }
+};
+
+#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
+
+
+const char *pvr2_config_get_name(enum pvr2_config cfg)
+{
+       switch (cfg) {
+       case pvr2_config_empty: return "empty";
+       case pvr2_config_mpeg: return "mpeg";
+       case pvr2_config_vbi: return "vbi";
+       case pvr2_config_radio: return "radio";
+       }
+       return "<unknown>";
+}
+
+
+struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *hdw)
+{
+       return hdw->usb_dev;
+}
+
+
+unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
+{
+       return hdw->serial_number;
+}
+
+
+struct pvr2_hdw *pvr2_hdw_find(int unit_number)
+{
+       if (unit_number < 0) return 0;
+       if (unit_number >= PVR_NUM) return 0;
+       return unit_pointers[unit_number];
+}
+
+
+int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
+{
+       return hdw->unit_number;
+}
+
+
+/* Attempt to locate one of the given set of files.  Messages are logged
+   appropriate to what has been found.  The return value will be 0 or
+   greater on success (it will be the index of the file name found) and
+   fw_entry will be filled in.  Otherwise a negative error is returned on
+   failure.  If the return value is -ENOENT then no viable firmware file
+   could be located. */
+static int pvr2_locate_firmware(struct pvr2_hdw *hdw,
+                               const struct firmware **fw_entry,
+                               const char *fwtypename,
+                               unsigned int fwcount,
+                               const char *fwnames[])
+{
+       unsigned int idx;
+       int ret = -EINVAL;
+       for (idx = 0; idx < fwcount; idx++) {
+               ret = request_firmware(fw_entry,
+                                      fwnames[idx],
+                                      &hdw->usb_dev->dev);
+               if (!ret) {
+                       trace_firmware("Located %s firmware: %s;"
+                                      " uploading...",
+                                      fwtypename,
+                                      fwnames[idx]);
+                       return idx;
+               }
+               if (ret == -ENOENT) continue;
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "request_firmware fatal error with code=%d",ret);
+               return ret;
+       }
+       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                  "***WARNING***"
+                  " Device %s firmware"
+                  " seems to be missing.",
+                  fwtypename);
+       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                  "Did you install the pvrusb2 firmware files"
+                  " in their proper location?");
+       if (fwcount == 1) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "request_firmware unable to locate %s file %s",
+                          fwtypename,fwnames[0]);
+       } else {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "request_firmware unable to locate"
+                          " one of the following %s files:",
+                          fwtypename);
+               for (idx = 0; idx < fwcount; idx++) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "request_firmware: Failed to find %s",
+                                  fwnames[idx]);
+               }
+       }
+       return ret;
+}
+
+
+/*
+ * pvr2_upload_firmware1().
+ *
+ * Send the 8051 firmware to the device.  After the upload, arrange for
+ * device to re-enumerate.
+ *
+ * NOTE : the pointer to the firmware data given by request_firmware()
+ * is not suitable for an usb transaction.
+ *
+ */
+int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
+{
+       const struct firmware *fw_entry = 0;
+       void  *fw_ptr;
+       unsigned int pipe;
+       int ret;
+       u16 address;
+       static const char *fw_files_29xxx[] = {
+               "v4l-pvrusb2-29xxx-01.fw",
+       };
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       static const char *fw_files_24xxx[] = {
+               "v4l-pvrusb2-24xxx-01.fw",
+       };
+#endif
+       static const struct pvr2_string_table fw_file_defs[] = {
+               [PVR2_HDW_TYPE_29XXX] = {
+                       fw_files_29xxx,
+                       sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
+               },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+               [PVR2_HDW_TYPE_24XXX] = {
+                       fw_files_24xxx,
+                       sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
+               },
+#endif
+       };
+       hdw->fw1_state = FW1_STATE_FAILED; // default result
+
+       trace_firmware("pvr2_upload_firmware1");
+
+       ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller",
+                                  fw_file_defs[hdw->hdw_type].cnt,
+                                  fw_file_defs[hdw->hdw_type].lst);
+       if (ret < 0) {
+               if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING;
+               return ret;
+       }
+
+       usb_settoggle(hdw->usb_dev, 0 & 0xf, !(0 & USB_DIR_IN), 0);
+       usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f));
+
+       pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
+
+       if (fw_entry->size != 0x2000){
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,"wrong fx2 firmware size");
+               release_firmware(fw_entry);
+               return -ENOMEM;
+       }
+
+       fw_ptr = kmalloc(0x800, GFP_KERNEL);
+       if (fw_ptr == NULL){
+               release_firmware(fw_entry);
+               return -ENOMEM;
+       }
+
+       /* We have to hold the CPU during firmware upload. */
+       pvr2_hdw_cpureset_assert(hdw,1);
+
+       /* upload the firmware to address 0000-1fff in 2048 (=0x800) bytes
+          chunk. */
+
+       ret = 0;
+       for(address = 0; address < fw_entry->size; address += 0x800) {
+               memcpy(fw_ptr, fw_entry->data + address, 0x800);
+               ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address,
+                                      0, fw_ptr, 0x800, HZ);
+       }
+
+       trace_firmware("Upload done, releasing device's CPU");
+
+       /* Now release the CPU.  It will disconnect and reconnect later. */
+       pvr2_hdw_cpureset_assert(hdw,0);
+
+       kfree(fw_ptr);
+       release_firmware(fw_entry);
+
+       trace_firmware("Upload done (%d bytes sent)",ret);
+
+       /* We should have written 8192 bytes */
+       if (ret == 8192) {
+               hdw->fw1_state = FW1_STATE_RELOAD;
+               return 0;
+       }
+
+       return -EIO;
+}
+
+
+/*
+ * pvr2_upload_firmware2()
+ *
+ * This uploads encoder firmware on endpoint 2.
+ *
+ */
+
+int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
+{
+       const struct firmware *fw_entry = 0;
+       void  *fw_ptr;
+       unsigned int pipe, fw_len, fw_done;
+       int actual_length;
+       int ret = 0;
+       int fwidx;
+       static const char *fw_files[] = {
+               CX2341X_FIRM_ENC_FILENAME,
+       };
+
+       trace_firmware("pvr2_upload_firmware2");
+
+       ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
+                                  sizeof(fw_files)/sizeof(fw_files[0]),
+                                  fw_files);
+       if (ret < 0) return ret;
+       fwidx = ret;
+       ret = 0;
+       /* Since we're about to completely reinitialize the encoder,
+          invalidate our cached copy of its configuration state.  Next
+          time we configure the encoder, then we'll fully configure it. */
+       hdw->enc_cur_valid = 0;
+
+       /* First prepare firmware loading */
+       ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
+       ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
+       ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
+       ret |= pvr2_hdw_cmd_deep_reset(hdw);
+       ret |= pvr2_write_register(hdw, 0xa064, 0x00000000); /*APU command*/
+       ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000408); /*gpio dir*/
+       ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
+       ret |= pvr2_write_register(hdw, 0x9058, 0xffffffed); /*VPU ctrl*/
+       ret |= pvr2_write_register(hdw, 0x9054, 0xfffffffd); /*reset hw blocks*/
+       ret |= pvr2_write_register(hdw, 0x07f8, 0x80000800); /*encoder SDRAM refresh*/
+       ret |= pvr2_write_register(hdw, 0x07fc, 0x0000001a); /*encoder SDRAM pre-charge*/
+       ret |= pvr2_write_register(hdw, 0x0700, 0x00000000); /*I2C clock*/
+       ret |= pvr2_write_register(hdw, 0xaa00, 0x00000000); /*unknown*/
+       ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
+       ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
+       ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
+       ret |= pvr2_write_u8(hdw, 0x52, 0);
+       ret |= pvr2_write_u16(hdw, 0x0600, 0);
+
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "firmware2 upload prep failed, ret=%d",ret);
+               release_firmware(fw_entry);
+               return ret;
+       }
+
+       /* Now send firmware */
+
+       fw_len = fw_entry->size;
+
+       if (fw_len % FIRMWARE_CHUNK_SIZE) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "size of %s firmware"
+                          " must be a multiple of 8192B",
+                          fw_files[fwidx]);
+               release_firmware(fw_entry);
+               return -1;
+       }
+
+       fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
+       if (fw_ptr == NULL){
+               release_firmware(fw_entry);
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "failed to allocate memory for firmware2 upload");
+               return -ENOMEM;
+       }
+
+       pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
+
+       for (fw_done = 0 ; (fw_done < fw_len) && !ret ;
+            fw_done += FIRMWARE_CHUNK_SIZE ) {
+               int i;
+               memcpy(fw_ptr, fw_entry->data + fw_done, FIRMWARE_CHUNK_SIZE);
+               /* Usbsnoop log  shows that we must swap bytes... */
+               for (i = 0; i < FIRMWARE_CHUNK_SIZE/4 ; i++)
+                       ((u32 *)fw_ptr)[i] = ___swab32(((u32 *)fw_ptr)[i]);
+
+               ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,
+                                   FIRMWARE_CHUNK_SIZE,
+                                   &actual_length, HZ);
+               ret |= (actual_length != FIRMWARE_CHUNK_SIZE);
+       }
+
+       trace_firmware("upload of %s : %i / %i ",
+                      fw_files[fwidx],fw_done,fw_len);
+
+       kfree(fw_ptr);
+       release_firmware(fw_entry);
+
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "firmware2 upload transfer failure");
+               return ret;
+       }
+
+       /* Finish upload */
+
+       ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
+       ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
+       ret |= pvr2_write_u16(hdw, 0x0600, 0);
+
+       if (ret) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "firmware2 upload post-proc failure");
+       } else {
+               hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE);
+       }
+       return ret;
+}
+
+
+#define FIRMWARE_RECOVERY_BITS \
+       ((1<<PVR2_SUBSYS_B_ENC_CFG) | \
+        (1<<PVR2_SUBSYS_B_ENC_RUN) | \
+        (1<<PVR2_SUBSYS_B_ENC_FIRMWARE) | \
+        (1<<PVR2_SUBSYS_B_USBSTREAM_RUN))
+
+/*
+
+  This single function is key to pretty much everything.  The pvrusb2
+  device can logically be viewed as a series of subsystems which can be
+  stopped / started or unconfigured / configured.  To get things streaming,
+  one must configure everything and start everything, but there may be
+  various reasons over time to deconfigure something or stop something.
+  This function handles all of this activity.  Everything EVERYWHERE that
+  must affect a subsystem eventually comes here to do the work.
+
+  The current state of all subsystems is represented by a single bit mask,
+  known as subsys_enabled_mask.  The bit positions are defined by the
+  PVR2_SUBSYS_xxxx macros, with one subsystem per bit position.  At any
+  time the set of configured or active subsystems can be queried just by
+  looking at that mask.  To change bits in that mask, this function here
+  must be called.  The "msk" argument indicates which bit positions to
+  change, and the "val" argument defines the new values for the positions
+  defined by "msk".
+
+  There is a priority ordering of starting / stopping things, and for
+  multiple requested changes, this function implements that ordering.
+  (Thus we will act on a request to load encoder firmware before we
+  configure the encoder.)  In addition to priority ordering, there is a
+  recovery strategy implemented here.  If a particular step fails and we
+  detect that failure, this function will clear the affected subsystem bits
+  and restart.  Thus we have a means for recovering from a dead encoder:
+  Clear all bits that correspond to subsystems that we need to restart /
+  reconfigure and start over.
+
+*/
+void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
+                                    unsigned long msk,unsigned long val)
+{
+       unsigned long nmsk;
+       unsigned long vmsk;
+       int ret;
+       unsigned int tryCount = 0;
+
+       if (!hdw->flag_ok) return;
+
+       msk &= PVR2_SUBSYS_ALL;
+       nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk);
+       nmsk &= PVR2_SUBSYS_ALL;
+
+       for (;;) {
+               tryCount++;
+               if (!((nmsk ^ hdw->subsys_enabled_mask) &
+                     PVR2_SUBSYS_ALL)) break;
+               if (tryCount > 4) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Too many retries when configuring device;"
+                                  " giving up");
+                       pvr2_hdw_render_useless(hdw);
+                       break;
+               }
+               if (tryCount > 1) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Retrying device reconfiguration");
+               }
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "subsys mask changing 0x%lx:0x%lx"
+                          " from 0x%lx to 0x%lx",
+                          msk,val,hdw->subsys_enabled_mask,nmsk);
+
+               vmsk = (nmsk ^ hdw->subsys_enabled_mask) &
+                       hdw->subsys_enabled_mask;
+               if (vmsk) {
+                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_encoder_stop");
+                               ret = pvr2_encoder_stop(hdw);
+                               if (ret) {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "Error recovery initiated");
+                                       hdw->subsys_enabled_mask &=
+                                               ~FIRMWARE_RECOVERY_BITS;
+                                       continue;
+                               }
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_hdw_cmd_usbstream(0)");
+                               pvr2_hdw_cmd_usbstream(hdw,0);
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " decoder disable");
+                               if (hdw->decoder_ctrl) {
+                                       hdw->decoder_ctrl->enable(
+                                               hdw->decoder_ctrl->ctxt,0);
+                               } else {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "WARNING:"
+                                                  " No decoder present");
+                               }
+                               hdw->subsys_enabled_mask &=
+                                       ~(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
+                       }
+                       if (vmsk & PVR2_SUBSYS_CFG_ALL) {
+                               hdw->subsys_enabled_mask &=
+                                       ~(vmsk & PVR2_SUBSYS_CFG_ALL);
+                       }
+               }
+               vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk;
+               if (vmsk) {
+                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_FIRMWARE)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_upload_firmware2");
+                               ret = pvr2_upload_firmware2(hdw);
+                               if (ret) {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "Failure uploading encoder"
+                                                  " firmware");
+                                       pvr2_hdw_render_useless(hdw);
+                                       break;
+                               }
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_CFG)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_encoder_configure");
+                               ret = pvr2_encoder_configure(hdw);
+                               if (ret) {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "Error recovery initiated");
+                                       hdw->subsys_enabled_mask &=
+                                               ~FIRMWARE_RECOVERY_BITS;
+                                       continue;
+                               }
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " decoder enable");
+                               if (hdw->decoder_ctrl) {
+                                       hdw->decoder_ctrl->enable(
+                                               hdw->decoder_ctrl->ctxt,!0);
+                               } else {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "WARNING:"
+                                                  " No decoder present");
+                               }
+                               hdw->subsys_enabled_mask |=
+                                       (1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_hdw_cmd_usbstream(1)");
+                               pvr2_hdw_cmd_usbstream(hdw,!0);
+                       }
+                       if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
+                               pvr2_trace(PVR2_TRACE_CTL,
+                                          "/*---TRACE_CTL----*/"
+                                          " pvr2_encoder_start");
+                               ret = pvr2_encoder_start(hdw);
+                               if (ret) {
+                                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                                  "Error recovery initiated");
+                                       hdw->subsys_enabled_mask &=
+                                               ~FIRMWARE_RECOVERY_BITS;
+                                       continue;
+                               }
+                       }
+               }
+       }
+}
+
+
+void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
+                            unsigned long msk,unsigned long val)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+void pvr2_hdw_subsys_bit_set(struct pvr2_hdw *hdw,unsigned long msk)
+{
+       pvr2_hdw_subsys_bit_chg(hdw,msk,msk);
+}
+
+
+void pvr2_hdw_subsys_bit_clr(struct pvr2_hdw *hdw,unsigned long msk)
+{
+       pvr2_hdw_subsys_bit_chg(hdw,msk,0);
+}
+
+
+unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw)
+{
+       return hdw->subsys_enabled_mask;
+}
+
+
+unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw)
+{
+       return hdw->subsys_stream_mask;
+}
+
+
+void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
+                                           unsigned long msk,
+                                           unsigned long val)
+{
+       unsigned long val2;
+       msk &= PVR2_SUBSYS_ALL;
+       val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk));
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx",
+                  msk,val,hdw->subsys_stream_mask,val2);
+       hdw->subsys_stream_mask = val2;
+}
+
+
+void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
+                                   unsigned long msk,
+                                   unsigned long val)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl)
+{
+       if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0;
+       if (enableFl) {
+               pvr2_trace(PVR2_TRACE_START_STOP,
+                          "/*--TRACE_STREAM--*/ enable");
+               pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0);
+       } else {
+               pvr2_trace(PVR2_TRACE_START_STOP,
+                          "/*--TRACE_STREAM--*/ disable");
+               pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
+       }
+       if (!hdw->flag_ok) return -EIO;
+       hdw->flag_streaming_enabled = enableFl != 0;
+       return 0;
+}
+
+
+int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
+{
+       return hdw->flag_streaming_enabled != 0;
+}
+
+
+int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag)
+{
+       int ret;
+       LOCK_TAKE(hdw->big_lock); do {
+               ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return ret;
+}
+
+
+int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw,
+                                    enum pvr2_config config)
+{
+       unsigned long sm = hdw->subsys_enabled_mask;
+       if (!hdw->flag_ok) return -EIO;
+       pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
+       hdw->config = config;
+       pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm);
+       return 0;
+}
+
+
+int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config)
+{
+       int ret;
+       if (!hdw->flag_ok) return -EIO;
+       LOCK_TAKE(hdw->big_lock);
+       ret = pvr2_hdw_set_stream_type_no_lock(hdw,config);
+       LOCK_GIVE(hdw->big_lock);
+       return ret;
+}
+
+
+static int get_default_tuner_type(struct pvr2_hdw *hdw)
+{
+       int unit_number = hdw->unit_number;
+       int tp = -1;
+       if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+               tp = tuner[unit_number];
+       }
+       if (tp < 0) return -EINVAL;
+       hdw->tuner_type = tp;
+       return 0;
+}
+
+
+static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw)
+{
+       int unit_number = hdw->unit_number;
+       int tp = 0;
+       if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+               tp = video_std[unit_number];
+       }
+       return tp;
+}
+
+
+static unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw)
+{
+       int unit_number = hdw->unit_number;
+       int tp = 0;
+       if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+               tp = tolerance[unit_number];
+       }
+       return tp;
+}
+
+
+static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
+{
+       /* Try a harmless request to fetch the eeprom's address over
+          endpoint 1.  See what happens.  Only the full FX2 image can
+          respond to this.  If this probe fails then likely the FX2
+          firmware needs be loaded. */
+       int result;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = 0xeb;
+               result = pvr2_send_request_ex(hdw,HZ*1,!0,
+                                          hdw->cmd_buffer,1,
+                                          hdw->cmd_buffer,1);
+               if (result < 0) break;
+       } while(0); LOCK_GIVE(hdw->ctl_lock);
+       if (result) {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Probe of device endpoint 1 result status %d",
+                          result);
+       } else {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Probe of device endpoint 1 succeeded");
+       }
+       return result == 0;
+}
+
+static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
+{
+       char buf[40];
+       unsigned int bcnt;
+       v4l2_std_id std1,std2;
+
+       std1 = get_default_standard(hdw);
+
+       bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "Supported video standard(s) reported by eeprom: %.*s",
+                  bcnt,buf);
+
+       hdw->std_mask_avail = hdw->std_mask_eeprom;
+
+       std2 = std1 & ~hdw->std_mask_avail;
+       if (std2) {
+               bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Expanding supported video standards"
+                          " to include: %.*s",
+                          bcnt,buf);
+               hdw->std_mask_avail |= std2;
+       }
+
+       pvr2_hdw_internal_set_std_avail(hdw);
+
+       if (std1) {
+               bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1);
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Initial video standard forced to %.*s",
+                          bcnt,buf);
+               hdw->std_mask_cur = std1;
+               hdw->std_dirty = !0;
+               pvr2_hdw_internal_find_stdenum(hdw);
+               return;
+       }
+
+       if (hdw->std_enum_cnt > 1) {
+               // Autoselect the first listed standard
+               hdw->std_enum_cur = 1;
+               hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id;
+               hdw->std_dirty = !0;
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Initial video standard auto-selected to %s",
+                          hdw->std_defs[hdw->std_enum_cur-1].name);
+               return;
+       }
+
+       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                  "Unable to select a viable initial video standard");
+}
+
+
+static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+{
+       int ret;
+       unsigned int idx;
+       struct pvr2_ctrl *cptr;
+       int reloadFl = 0;
+       if (!reloadFl) {
+               reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
+                           == 0);
+               if (reloadFl) {
+                       pvr2_trace(PVR2_TRACE_INIT,
+                                  "USB endpoint config looks strange"
+                                  "; possibly firmware needs to be loaded");
+               }
+       }
+       if (!reloadFl) {
+               reloadFl = !pvr2_hdw_check_firmware(hdw);
+               if (reloadFl) {
+                       pvr2_trace(PVR2_TRACE_INIT,
+                                  "Check for FX2 firmware failed"
+                                  "; possibly firmware needs to be loaded");
+               }
+       }
+       if (reloadFl) {
+               if (pvr2_upload_firmware1(hdw) != 0) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Failure uploading firmware1");
+               }
+               return;
+       }
+       hdw->fw1_state = FW1_STATE_OK;
+
+       if (initusbreset) {
+               pvr2_hdw_device_reset(hdw);
+       }
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) {
+               request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]);
+       }
+
+       pvr2_hdw_cmd_powerup(hdw);
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       if (pvr2_upload_firmware2(hdw)){
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
+               pvr2_hdw_render_useless(hdw);
+               return;
+       }
+
+       // This step MUST happen after the earlier powerup step.
+       pvr2_i2c_core_init(hdw);
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
+               cptr = hdw->controls + idx;
+               if (cptr->info->skip_init) continue;
+               if (!cptr->info->set_value) continue;
+               cptr->info->set_value(cptr,~0,cptr->info->default_value);
+       }
+
+       // Do not use pvr2_reset_ctl_endpoints() here.  It is not
+       // thread-safe against the normal pvr2_send_request() mechanism.
+       // (We should make it thread safe).
+
+       ret = pvr2_hdw_get_eeprom_addr(hdw);
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+       if (ret < 0) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Unable to determine location of eeprom, skipping");
+       } else {
+               hdw->eeprom_addr = ret;
+               pvr2_eeprom_analyze(hdw);
+               if (!pvr2_hdw_dev_ok(hdw)) return;
+       }
+
+       pvr2_hdw_setup_std(hdw);
+
+       if (!get_default_tuner_type(hdw)) {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "pvr2_hdw_setup: Tuner type overridden to %d",
+                          hdw->tuner_type);
+       }
+
+       hdw->tuner_updated = !0;
+       pvr2_i2c_core_check_stale(hdw);
+       hdw->tuner_updated = 0;
+
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       pvr2_hdw_commit_ctl_internal(hdw);
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       hdw->vid_stream = pvr2_stream_create();
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "pvr2_hdw_setup: video stream is %p",hdw->vid_stream);
+       if (hdw->vid_stream) {
+               idx = get_default_error_tolerance(hdw);
+               if (idx) {
+                       pvr2_trace(PVR2_TRACE_INIT,
+                                  "pvr2_hdw_setup: video stream %p"
+                                  " setting tolerance %u",
+                                  hdw->vid_stream,idx);
+               }
+               pvr2_stream_setup(hdw->vid_stream,hdw->usb_dev,
+                                 PVR2_VID_ENDPOINT,idx);
+       }
+
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       /* Make sure everything is up to date */
+       pvr2_i2c_core_sync(hdw);
+
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       hdw->flag_init_ok = !0;
+}
+
+
+int pvr2_hdw_setup(struct pvr2_hdw *hdw)
+{
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw);
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_hdw_setup_low(hdw);
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d",
+                          hdw,hdw->flag_ok,hdw->flag_init_ok);
+               if (pvr2_hdw_dev_ok(hdw)) {
+                       if (pvr2_hdw_init_ok(hdw)) {
+                               pvr2_trace(
+                                       PVR2_TRACE_INFO,
+                                       "Device initialization"
+                                       " completed successfully.");
+                               break;
+                       }
+                       if (hdw->fw1_state == FW1_STATE_RELOAD) {
+                               pvr2_trace(
+                                       PVR2_TRACE_INFO,
+                                       "Device microcontroller firmware"
+                                       " (re)loaded; it should now reset"
+                                       " and reconnect.");
+                               break;
+                       }
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "Device initialization was not successful.");
+                       if (hdw->fw1_state == FW1_STATE_MISSING) {
+                               pvr2_trace(
+                                       PVR2_TRACE_ERROR_LEGS,
+                                       "Giving up since device"
+                                       " microcontroller firmware"
+                                       " appears to be missing.");
+                               break;
+                       }
+               }
+               if (procreload) {
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "Attempting pvrusb2 recovery by reloading"
+                               " primary firmware.");
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "If this works, device should disconnect"
+                               " and reconnect in a sane state.");
+                       hdw->fw1_state = FW1_STATE_UNKNOWN;
+                       pvr2_upload_firmware1(hdw);
+               } else {
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "***WARNING*** pvrusb2 device hardware"
+                               " appears to be jammed"
+                               " and I can't clear it.");
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "You might need to power cycle"
+                               " the pvrusb2 device"
+                               " in order to recover.");
+               }
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw);
+       return hdw->flag_init_ok;
+}
+
+
+/* Create and return a structure for interacting with the underlying
+   hardware */
+struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+                                const struct usb_device_id *devid)
+{
+       unsigned int idx,cnt1,cnt2;
+       struct pvr2_hdw *hdw;
+       unsigned int hdw_type;
+       int valid_std_mask;
+       struct pvr2_ctrl *cptr;
+       __u8 ifnum;
+       struct v4l2_queryctrl qctrl;
+       struct pvr2_ctl_info *ciptr;
+
+       hdw_type = devid - pvr2_device_table;
+       if (hdw_type >=
+           sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Bogus device type of %u reported",hdw_type);
+               return 0;
+       }
+
+       hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
+                  hdw,pvr2_device_names[hdw_type]);
+       if (!hdw) goto fail;
+       memset(hdw,0,sizeof(*hdw));
+       cx2341x_fill_defaults(&hdw->enc_ctl_state);
+
+       hdw->control_cnt = CTRLDEF_COUNT;
+       hdw->control_cnt += MPEGDEF_COUNT;
+       hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+                               GFP_KERNEL);
+       if (!hdw->controls) goto fail;
+       memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
+       hdw->hdw_type = hdw_type;
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               cptr->hdw = hdw;
+       }
+       for (idx = 0; idx < 32; idx++) {
+               hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx];
+       }
+       for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
+               cptr = hdw->controls + idx;
+               cptr->info = control_defs+idx;
+       }
+       /* Define and configure additional controls from cx2341x module. */
+       hdw->mpeg_ctrl_info = kmalloc(
+               sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
+       if (!hdw->mpeg_ctrl_info) goto fail;
+       memset(hdw->mpeg_ctrl_info,0,
+              sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
+       for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
+               cptr = hdw->controls + idx + CTRLDEF_COUNT;
+               ciptr = &(hdw->mpeg_ctrl_info[idx].info);
+               ciptr->desc = hdw->mpeg_ctrl_info[idx].desc;
+               ciptr->name = mpeg_ids[idx].strid;
+               ciptr->v4l_id = mpeg_ids[idx].id;
+               ciptr->skip_init = !0;
+               ciptr->get_value = ctrl_cx2341x_get;
+               ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags;
+               ciptr->is_dirty = ctrl_cx2341x_is_dirty;
+               if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty;
+               qctrl.id = ciptr->v4l_id;
+               cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl);
+               if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) {
+                       ciptr->set_value = ctrl_cx2341x_set;
+               }
+               strncpy(hdw->mpeg_ctrl_info[idx].desc,qctrl.name,
+                       PVR2_CTLD_INFO_DESC_SIZE);
+               hdw->mpeg_ctrl_info[idx].desc[PVR2_CTLD_INFO_DESC_SIZE-1] = 0;
+               ciptr->default_value = qctrl.default_value;
+               switch (qctrl.type) {
+               default:
+               case V4L2_CTRL_TYPE_INTEGER:
+                       ciptr->type = pvr2_ctl_int;
+                       ciptr->def.type_int.min_value = qctrl.minimum;
+                       ciptr->def.type_int.max_value = qctrl.maximum;
+                       break;
+               case V4L2_CTRL_TYPE_BOOLEAN:
+                       ciptr->type = pvr2_ctl_bool;
+                       break;
+               case V4L2_CTRL_TYPE_MENU:
+                       ciptr->type = pvr2_ctl_enum;
+                       ciptr->def.type_enum.value_names =
+                               cx2341x_ctrl_get_menu(ciptr->v4l_id);
+                       for (cnt1 = 0;
+                            ciptr->def.type_enum.value_names[cnt1] != NULL;
+                            cnt1++) { }
+                       ciptr->def.type_enum.count = cnt1;
+                       break;
+               }
+               cptr->info = ciptr;
+       }
+
+       // Initialize video standard enum dynamic control
+       cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM);
+       if (cptr) {
+               memcpy(&hdw->std_info_enum,cptr->info,
+                      sizeof(hdw->std_info_enum));
+               cptr->info = &hdw->std_info_enum;
+
+       }
+       // Initialize control data regarding video standard masks
+       valid_std_mask = pvr2_std_get_usable();
+       for (idx = 0; idx < 32; idx++) {
+               if (!(valid_std_mask & (1 << idx))) continue;
+               cnt1 = pvr2_std_id_to_str(
+                       hdw->std_mask_names[idx],
+                       sizeof(hdw->std_mask_names[idx])-1,
+                       1 << idx);
+               hdw->std_mask_names[idx][cnt1] = 0;
+       }
+       cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL);
+       if (cptr) {
+               memcpy(&hdw->std_info_avail,cptr->info,
+                      sizeof(hdw->std_info_avail));
+               cptr->info = &hdw->std_info_avail;
+               hdw->std_info_avail.def.type_bitmask.bit_names =
+                       hdw->std_mask_ptrs;
+               hdw->std_info_avail.def.type_bitmask.valid_bits =
+                       valid_std_mask;
+       }
+       cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR);
+       if (cptr) {
+               memcpy(&hdw->std_info_cur,cptr->info,
+                      sizeof(hdw->std_info_cur));
+               cptr->info = &hdw->std_info_cur;
+               hdw->std_info_cur.def.type_bitmask.bit_names =
+                       hdw->std_mask_ptrs;
+               hdw->std_info_avail.def.type_bitmask.valid_bits =
+                       valid_std_mask;
+       }
+
+       hdw->eeprom_addr = -1;
+       hdw->unit_number = -1;
+       hdw->v4l_minor_number = -1;
+       hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
+       if (!hdw->ctl_write_buffer) goto fail;
+       hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
+       if (!hdw->ctl_read_buffer) goto fail;
+       hdw->ctl_write_urb = usb_alloc_urb(0,GFP_KERNEL);
+       if (!hdw->ctl_write_urb) goto fail;
+       hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL);
+       if (!hdw->ctl_read_urb) goto fail;
+
+       down(&pvr2_unit_sem); do {
+               for (idx = 0; idx < PVR_NUM; idx++) {
+                       if (unit_pointers[idx]) continue;
+                       hdw->unit_number = idx;
+                       unit_pointers[idx] = hdw;
+                       break;
+               }
+       } while (0); up(&pvr2_unit_sem);
+
+       cnt1 = 0;
+       cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2");
+       cnt1 += cnt2;
+       if (hdw->unit_number >= 0) {
+               cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"_%c",
+                                ('a' + hdw->unit_number));
+               cnt1 += cnt2;
+       }
+       if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1;
+       hdw->name[cnt1] = 0;
+
+       pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
+                  hdw->unit_number,hdw->name);
+
+       hdw->tuner_type = -1;
+       hdw->flag_ok = !0;
+       /* Initialize the mask of subsystems that we will shut down when we
+          stop streaming. */
+       hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL;
+       hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+
+       pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx",
+                  hdw->subsys_stream_mask);
+
+       hdw->usb_intf = intf;
+       hdw->usb_dev = interface_to_usbdev(intf);
+
+       ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
+       usb_set_interface(hdw->usb_dev,ifnum,0);
+
+       mutex_init(&hdw->ctl_lock_mutex);
+       mutex_init(&hdw->big_lock_mutex);
+
+       return hdw;
+ fail:
+       if (hdw) {
+               if (hdw->ctl_read_urb) usb_free_urb(hdw->ctl_read_urb);
+               if (hdw->ctl_write_urb) usb_free_urb(hdw->ctl_write_urb);
+               if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer);
+               if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer);
+               if (hdw->controls) kfree(hdw->controls);
+               if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
+               kfree(hdw);
+       }
+       return 0;
+}
+
+
+/* Remove _all_ associations between this driver and the underlying USB
+   layer. */
+void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
+{
+       if (hdw->flag_disconnected) return;
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_remove_usb_stuff: hdw=%p",hdw);
+       if (hdw->ctl_read_urb) {
+               usb_kill_urb(hdw->ctl_read_urb);
+               usb_free_urb(hdw->ctl_read_urb);
+               hdw->ctl_read_urb = 0;
+       }
+       if (hdw->ctl_write_urb) {
+               usb_kill_urb(hdw->ctl_write_urb);
+               usb_free_urb(hdw->ctl_write_urb);
+               hdw->ctl_write_urb = 0;
+       }
+       if (hdw->ctl_read_buffer) {
+               kfree(hdw->ctl_read_buffer);
+               hdw->ctl_read_buffer = 0;
+       }
+       if (hdw->ctl_write_buffer) {
+               kfree(hdw->ctl_write_buffer);
+               hdw->ctl_write_buffer = 0;
+       }
+       pvr2_hdw_render_useless_unlocked(hdw);
+       hdw->flag_disconnected = !0;
+       hdw->usb_dev = 0;
+       hdw->usb_intf = 0;
+}
+
+
+/* Destroy hardware interaction structure */
+void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
+{
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
+       if (hdw->fw_buffer) {
+               kfree(hdw->fw_buffer);
+               hdw->fw_buffer = 0;
+       }
+       if (hdw->vid_stream) {
+               pvr2_stream_destroy(hdw->vid_stream);
+               hdw->vid_stream = 0;
+       }
+       if (hdw->audio_stat) {
+               hdw->audio_stat->detach(hdw->audio_stat->ctxt);
+       }
+       if (hdw->decoder_ctrl) {
+               hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
+       }
+       pvr2_i2c_core_done(hdw);
+       pvr2_hdw_remove_usb_stuff(hdw);
+       down(&pvr2_unit_sem); do {
+               if ((hdw->unit_number >= 0) &&
+                   (hdw->unit_number < PVR_NUM) &&
+                   (unit_pointers[hdw->unit_number] == hdw)) {
+                       unit_pointers[hdw->unit_number] = 0;
+               }
+       } while (0); up(&pvr2_unit_sem);
+       if (hdw->controls) kfree(hdw->controls);
+       if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
+       if (hdw->std_defs) kfree(hdw->std_defs);
+       if (hdw->std_enum_names) kfree(hdw->std_enum_names);
+       kfree(hdw);
+}
+
+
+int pvr2_hdw_init_ok(struct pvr2_hdw *hdw)
+{
+       return hdw->flag_init_ok;
+}
+
+
+int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw)
+{
+       return (hdw && hdw->flag_ok);
+}
+
+
+/* Called when hardware has been unplugged */
+void pvr2_hdw_disconnect(struct pvr2_hdw *hdw)
+{
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw);
+       LOCK_TAKE(hdw->big_lock);
+       LOCK_TAKE(hdw->ctl_lock);
+       pvr2_hdw_remove_usb_stuff(hdw);
+       LOCK_GIVE(hdw->ctl_lock);
+       LOCK_GIVE(hdw->big_lock);
+}
+
+
+// Attempt to autoselect an appropriate value for std_enum_cur given
+// whatever is currently in std_mask_cur
+void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw)
+{
+       unsigned int idx;
+       for (idx = 1; idx < hdw->std_enum_cnt; idx++) {
+               if (hdw->std_defs[idx-1].id == hdw->std_mask_cur) {
+                       hdw->std_enum_cur = idx;
+                       return;
+               }
+       }
+       hdw->std_enum_cur = 0;
+}
+
+
+// Calculate correct set of enumerated standards based on currently known
+// set of available standards bits.
+void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw)
+{
+       struct v4l2_standard *newstd;
+       unsigned int std_cnt;
+       unsigned int idx;
+
+       newstd = pvr2_std_create_enum(&std_cnt,hdw->std_mask_avail);
+
+       if (hdw->std_defs) {
+               kfree(hdw->std_defs);
+               hdw->std_defs = 0;
+       }
+       hdw->std_enum_cnt = 0;
+       if (hdw->std_enum_names) {
+               kfree(hdw->std_enum_names);
+               hdw->std_enum_names = 0;
+       }
+
+       if (!std_cnt) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "WARNING: Failed to identify any viable standards");
+       }
+       hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL);
+       hdw->std_enum_names[0] = "none";
+       for (idx = 0; idx < std_cnt; idx++) {
+               hdw->std_enum_names[idx+1] =
+                       newstd[idx].name;
+       }
+       // Set up the dynamic control for this standard
+       hdw->std_info_enum.def.type_enum.value_names = hdw->std_enum_names;
+       hdw->std_info_enum.def.type_enum.count = std_cnt+1;
+       hdw->std_defs = newstd;
+       hdw->std_enum_cnt = std_cnt+1;
+       hdw->std_enum_cur = 0;
+       hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;
+}
+
+
+int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,
+                              struct v4l2_standard *std,
+                              unsigned int idx)
+{
+       int ret = -EINVAL;
+       if (!idx) return ret;
+       LOCK_TAKE(hdw->big_lock); do {
+               if (idx >= hdw->std_enum_cnt) break;
+               idx--;
+               memcpy(std,hdw->std_defs+idx,sizeof(*std));
+               ret = 0;
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return ret;
+}
+
+
+/* Get the number of defined controls */
+unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw)
+{
+       return hdw->control_cnt;
+}
+
+
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *hdw,
+                                            unsigned int idx)
+{
+       if (idx >= hdw->control_cnt) return 0;
+       return hdw->controls + idx;
+}
+
+
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *hdw,
+                                         unsigned int ctl_id)
+{
+       struct pvr2_ctrl *cptr;
+       unsigned int idx;
+       int i;
+
+       /* This could be made a lot more efficient, but for now... */
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               i = cptr->info->internal_id;
+               if (i && (i == ctl_id)) return cptr;
+       }
+       return 0;
+}
+
+
+/* Given a V4L ID, retrieve the control structure associated with it. */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id)
+{
+       struct pvr2_ctrl *cptr;
+       unsigned int idx;
+       int i;
+
+       /* This could be made a lot more efficient, but for now... */
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               i = cptr->info->v4l_id;
+               if (i && (i == ctl_id)) return cptr;
+       }
+       return 0;
+}
+
+
+/* Given a V4L ID for its immediate predecessor, retrieve the control
+   structure associated with it. */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *hdw,
+                                           unsigned int ctl_id)
+{
+       struct pvr2_ctrl *cptr,*cp2;
+       unsigned int idx;
+       int i;
+
+       /* This could be made a lot more efficient, but for now... */
+       cp2 = 0;
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               i = cptr->info->v4l_id;
+               if (!i) continue;
+               if (i <= ctl_id) continue;
+               if (cp2 && (cp2->info->v4l_id < i)) continue;
+               cp2 = cptr;
+       }
+       return cp2;
+       return 0;
+}
+
+
+static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
+{
+       switch (tp) {
+       case pvr2_ctl_int: return "integer";
+       case pvr2_ctl_enum: return "enum";
+       case pvr2_ctl_bool: return "boolean";
+       case pvr2_ctl_bitmask: return "bitmask";
+       }
+       return "";
+}
+
+
+/* Commit all control changes made up to this point.  Subsystems can be
+   indirectly affected by these changes.  For a given set of things being
+   committed, we'll clear the affected subsystem bits and then once we're
+   done committing everything we'll make a request to restore the subsystem
+   state(s) back to their previous value before this function was called.
+   Thus we can automatically reconfigure affected pieces of the driver as
+   controls are changed. */
+int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
+{
+       unsigned long saved_subsys_mask = hdw->subsys_enabled_mask;
+       unsigned long stale_subsys_mask = 0;
+       unsigned int idx;
+       struct pvr2_ctrl *cptr;
+       int value;
+       int commit_flag = 0;
+       char buf[100];
+       unsigned int bcnt,ccnt;
+
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               if (cptr->info->is_dirty == 0) continue;
+               if (!cptr->info->is_dirty(cptr)) continue;
+               if (!commit_flag) {
+                       commit_flag = !0;
+               }
+
+               bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
+                                cptr->info->name);
+               value = 0;
+               cptr->info->get_value(cptr,&value);
+               pvr2_ctrl_value_to_sym_internal(cptr,~0,value,
+                                               buf+bcnt,
+                                               sizeof(buf)-bcnt,&ccnt);
+               bcnt += ccnt;
+               bcnt += scnprintf(buf+bcnt,sizeof(buf)-bcnt," <%s>",
+                                 get_ctrl_typename(cptr->info->type));
+               pvr2_trace(PVR2_TRACE_CTL,
+                          "/*--TRACE_COMMIT--*/ %.*s",
+                          bcnt,buf);
+       }
+
+       if (!commit_flag) {
+               /* Nothing has changed */
+               return 0;
+       }
+
+       /* When video standard changes, reset the hres and vres values -
+          but if the user has pending changes there, then let the changes
+          take priority. */
+       if (hdw->std_dirty) {
+               /* Rewrite the vertical resolution to be appropriate to the
+                  video standard that has been selected. */
+               int nvres;
+               if (hdw->std_mask_cur & V4L2_STD_525_60) {
+                       nvres = 480;
+               } else {
+                       nvres = 576;
+               }
+               if (nvres != hdw->res_ver_val) {
+                       hdw->res_ver_val = nvres;
+                       hdw->res_ver_dirty = !0;
+               }
+       }
+
+       if (hdw->std_dirty ||
+           0) {
+               /* If any of this changes, then the encoder needs to be
+                  reconfigured, and we need to reset the stream. */
+               stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+               stale_subsys_mask |= hdw->subsys_stream_mask;
+       }
+
+       if (hdw->srate_dirty) {
+               /* Write new sample rate into control structure since
+                * the master copy is stale.  We must track srate
+                * separate from the mpeg control structure because
+                * other logic also uses this value. */
+               struct v4l2_ext_controls cs;
+               struct v4l2_ext_control c1;
+               memset(&cs,0,sizeof(cs));
+               memset(&c1,0,sizeof(c1));
+               cs.controls = &c1;
+               cs.count = 1;
+               c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ;
+               c1.value = hdw->srate_val;
+               cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS);
+       }
+
+       /* Scan i2c core at this point - before we clear all the dirty
+          bits.  Various parts of the i2c core will notice dirty bits as
+          appropriate and arrange to broadcast or directly send updates to
+          the client drivers in order to keep everything in sync */
+       pvr2_i2c_core_check_stale(hdw);
+
+       for (idx = 0; idx < hdw->control_cnt; idx++) {
+               cptr = hdw->controls + idx;
+               if (!cptr->info->clear_dirty) continue;
+               cptr->info->clear_dirty(cptr);
+       }
+
+       /* Now execute i2c core update */
+       pvr2_i2c_core_sync(hdw);
+
+       pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0);
+       pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask);
+
+       return 0;
+}
+
+
+int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_hdw_commit_ctl_internal(hdw);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return 0;
+}
+
+
+void pvr2_hdw_poll(struct pvr2_hdw *hdw)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_i2c_core_sync(hdw);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw,
+                                void (*func)(void *),
+                                void *data)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               hdw->poll_trigger_func = func;
+               hdw->poll_trigger_data = data;
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw)
+{
+       if (hdw->poll_trigger_func) {
+               hdw->poll_trigger_func(hdw->poll_trigger_data);
+       }
+}
+
+
+void pvr2_hdw_poll_trigger(struct pvr2_hdw *hdw)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               pvr2_hdw_poll_trigger_unlocked(hdw);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+/* Return name for this driver instance */
+const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
+{
+       return hdw->name;
+}
+
+
+/* Return bit mask indicating signal status */
+unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
+{
+       unsigned int msk = 0;
+       switch (hdw->input_val) {
+       case PVR2_CVAL_INPUT_TV:
+       case PVR2_CVAL_INPUT_RADIO:
+               if (hdw->decoder_ctrl &&
+                   hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
+                       msk |= PVR2_SIGNAL_OK;
+                       if (hdw->audio_stat &&
+                           hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
+                               if (hdw->flag_stereo) {
+                                       msk |= PVR2_SIGNAL_STEREO;
+                               }
+                               if (hdw->flag_bilingual) {
+                                       msk |= PVR2_SIGNAL_SAP;
+                               }
+                       }
+               }
+               break;
+       default:
+               msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
+       }
+       return msk;
+}
+
+
+int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
+{
+       int result;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = 0x0b;
+               result = pvr2_send_request(hdw,
+                                          hdw->cmd_buffer,1,
+                                          hdw->cmd_buffer,1);
+               if (result < 0) break;
+               result = (hdw->cmd_buffer[0] != 0);
+       } while(0); LOCK_GIVE(hdw->ctl_lock);
+       return result;
+}
+
+
+/* Return bit mask indicating signal status */
+unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
+{
+       unsigned int msk = 0;
+       LOCK_TAKE(hdw->big_lock); do {
+               msk = pvr2_hdw_get_signal_status_internal(hdw);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return msk;
+}
+
+
+/* Get handle to video output stream */
+struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp)
+{
+       return hp->vid_stream;
+}
+
+
+void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
+{
+       int nr = pvr2_hdw_get_unit_number(hdw);
+       LOCK_TAKE(hdw->big_lock); do {
+               hdw->log_requested = !0;
+               printk(KERN_INFO "pvrusb2: =================  START STATUS CARD #%d  =================\n", nr);
+               pvr2_i2c_core_check_stale(hdw);
+               hdw->log_requested = 0;
+               pvr2_i2c_core_sync(hdw);
+               pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
+               cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
+               printk(KERN_INFO "pvrusb2: ==================  END STATUS CARD #%d  ==================\n", nr);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
+{
+       int ret;
+       u16 address;
+       unsigned int pipe;
+       LOCK_TAKE(hdw->big_lock); do {
+               if ((hdw->fw_buffer == 0) == !enable_flag) break;
+
+               if (!enable_flag) {
+                       pvr2_trace(PVR2_TRACE_FIRMWARE,
+                                  "Cleaning up after CPU firmware fetch");
+                       kfree(hdw->fw_buffer);
+                       hdw->fw_buffer = 0;
+                       hdw->fw_size = 0;
+                       /* Now release the CPU.  It will disconnect and
+                          reconnect later. */
+                       pvr2_hdw_cpureset_assert(hdw,0);
+                       break;
+               }
+
+               pvr2_trace(PVR2_TRACE_FIRMWARE,
+                          "Preparing to suck out CPU firmware");
+               hdw->fw_size = 0x2000;
+               hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
+               if (!hdw->fw_buffer) {
+                       hdw->fw_size = 0;
+                       break;
+               }
+
+               memset(hdw->fw_buffer,0,hdw->fw_size);
+
+               /* We have to hold the CPU during firmware upload. */
+               pvr2_hdw_cpureset_assert(hdw,1);
+
+               /* download the firmware from address 0000-1fff in 2048
+                  (=0x800) bytes chunk. */
+
+               pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware");
+               pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
+               for(address = 0; address < hdw->fw_size; address += 0x800) {
+                       ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0,
+                                             address,0,
+                                             hdw->fw_buffer+address,0x800,HZ);
+                       if (ret < 0) break;
+               }
+
+               pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware");
+
+       } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+/* Return true if we're in a mode for retrieval CPU firmware */
+int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw)
+{
+       return hdw->fw_buffer != 0;
+}
+
+
+int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs,
+                      char *buf,unsigned int cnt)
+{
+       int ret = -EINVAL;
+       LOCK_TAKE(hdw->big_lock); do {
+               if (!buf) break;
+               if (!cnt) break;
+
+               if (!hdw->fw_buffer) {
+                       ret = -EIO;
+                       break;
+               }
+
+               if (offs >= hdw->fw_size) {
+                       pvr2_trace(PVR2_TRACE_FIRMWARE,
+                                  "Read firmware data offs=%d EOF",
+                                  offs);
+                       ret = 0;
+                       break;
+               }
+
+               if (offs + cnt > hdw->fw_size) cnt = hdw->fw_size - offs;
+
+               memcpy(buf,hdw->fw_buffer+offs,cnt);
+
+               pvr2_trace(PVR2_TRACE_FIRMWARE,
+                          "Read firmware data offs=%d cnt=%d",
+                          offs,cnt);
+               ret = cnt;
+       } while (0); LOCK_GIVE(hdw->big_lock);
+
+       return ret;
+}
+
+
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw)
+{
+       return hdw->v4l_minor_number;
+}
+
+
+/* Store the v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v)
+{
+       hdw->v4l_minor_number = v;
+}
+
+
+void pvr2_reset_ctl_endpoints(struct pvr2_hdw *hdw)
+{
+       if (!hdw->usb_dev) return;
+       usb_settoggle(hdw->usb_dev, PVR2_CTL_WRITE_ENDPOINT & 0xf,
+                     !(PVR2_CTL_WRITE_ENDPOINT & USB_DIR_IN), 0);
+       usb_settoggle(hdw->usb_dev, PVR2_CTL_READ_ENDPOINT & 0xf,
+                     !(PVR2_CTL_READ_ENDPOINT & USB_DIR_IN), 0);
+       usb_clear_halt(hdw->usb_dev,
+                      usb_rcvbulkpipe(hdw->usb_dev,
+                                      PVR2_CTL_READ_ENDPOINT & 0x7f));
+       usb_clear_halt(hdw->usb_dev,
+                      usb_sndbulkpipe(hdw->usb_dev,
+                                      PVR2_CTL_WRITE_ENDPOINT & 0x7f));
+}
+
+
+static void pvr2_ctl_write_complete(struct urb *urb, struct pt_regs *regs)
+{
+       struct pvr2_hdw *hdw = urb->context;
+       hdw->ctl_write_pend_flag = 0;
+       if (hdw->ctl_read_pend_flag) return;
+       complete(&hdw->ctl_done);
+}
+
+
+static void pvr2_ctl_read_complete(struct urb *urb, struct pt_regs *regs)
+{
+       struct pvr2_hdw *hdw = urb->context;
+       hdw->ctl_read_pend_flag = 0;
+       if (hdw->ctl_write_pend_flag) return;
+       complete(&hdw->ctl_done);
+}
+
+
+static void pvr2_ctl_timeout(unsigned long data)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+       if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) {
+               hdw->ctl_timeout_flag = !0;
+               if (hdw->ctl_write_pend_flag && hdw->ctl_write_urb) {
+                       usb_unlink_urb(hdw->ctl_write_urb);
+               }
+               if (hdw->ctl_read_pend_flag && hdw->ctl_read_urb) {
+                       usb_unlink_urb(hdw->ctl_read_urb);
+               }
+       }
+}
+
+
+int pvr2_send_request_ex(struct pvr2_hdw *hdw,
+                        unsigned int timeout,int probe_fl,
+                        void *write_data,unsigned int write_len,
+                        void *read_data,unsigned int read_len)
+{
+       unsigned int idx;
+       int status = 0;
+       struct timer_list timer;
+       if (!hdw->ctl_lock_held) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Attempted to execute control transfer"
+                          " without lock!!");
+               return -EDEADLK;
+       }
+       if ((!hdw->flag_ok) && !probe_fl) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Attempted to execute control transfer"
+                          " when device not ok");
+               return -EIO;
+       }
+       if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) {
+               if (!probe_fl) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Attempted to execute control transfer"
+                                  " when USB is disconnected");
+               }
+               return -ENOTTY;
+       }
+
+       /* Ensure that we have sane parameters */
+       if (!write_data) write_len = 0;
+       if (!read_data) read_len = 0;
+       if (write_len > PVR2_CTL_BUFFSIZE) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Attempted to execute %d byte"
+                       " control-write transfer (limit=%d)",
+                       write_len,PVR2_CTL_BUFFSIZE);
+               return -EINVAL;
+       }
+       if (read_len > PVR2_CTL_BUFFSIZE) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Attempted to execute %d byte"
+                       " control-read transfer (limit=%d)",
+                       write_len,PVR2_CTL_BUFFSIZE);
+               return -EINVAL;
+       }
+       if ((!write_len) && (!read_len)) {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "Attempted to execute null control transfer?");
+               return -EINVAL;
+       }
+
+
+       hdw->cmd_debug_state = 1;
+       if (write_len) {
+               hdw->cmd_debug_code = ((unsigned char *)write_data)[0];
+       } else {
+               hdw->cmd_debug_code = 0;
+       }
+       hdw->cmd_debug_write_len = write_len;
+       hdw->cmd_debug_read_len = read_len;
+
+       /* Initialize common stuff */
+       init_completion(&hdw->ctl_done);
+       hdw->ctl_timeout_flag = 0;
+       hdw->ctl_write_pend_flag = 0;
+       hdw->ctl_read_pend_flag = 0;
+       init_timer(&timer);
+       timer.expires = jiffies + timeout;
+       timer.data = (unsigned long)hdw;
+       timer.function = pvr2_ctl_timeout;
+
+       if (write_len) {
+               hdw->cmd_debug_state = 2;
+               /* Transfer write data to internal buffer */
+               for (idx = 0; idx < write_len; idx++) {
+                       hdw->ctl_write_buffer[idx] =
+                               ((unsigned char *)write_data)[idx];
+               }
+               /* Initiate a write request */
+               usb_fill_bulk_urb(hdw->ctl_write_urb,
+                                 hdw->usb_dev,
+                                 usb_sndbulkpipe(hdw->usb_dev,
+                                                 PVR2_CTL_WRITE_ENDPOINT),
+                                 hdw->ctl_write_buffer,
+                                 write_len,
+                                 pvr2_ctl_write_complete,
+                                 hdw);
+               hdw->ctl_write_urb->actual_length = 0;
+               hdw->ctl_write_pend_flag = !0;
+               status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL);
+               if (status < 0) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Failed to submit write-control"
+                                  " URB status=%d",status);
+                       hdw->ctl_write_pend_flag = 0;
+                       goto done;
+               }
+       }
+
+       if (read_len) {
+               hdw->cmd_debug_state = 3;
+               memset(hdw->ctl_read_buffer,0x43,read_len);
+               /* Initiate a read request */
+               usb_fill_bulk_urb(hdw->ctl_read_urb,
+                                 hdw->usb_dev,
+                                 usb_rcvbulkpipe(hdw->usb_dev,
+                                                 PVR2_CTL_READ_ENDPOINT),
+                                 hdw->ctl_read_buffer,
+                                 read_len,
+                                 pvr2_ctl_read_complete,
+                                 hdw);
+               hdw->ctl_read_urb->actual_length = 0;
+               hdw->ctl_read_pend_flag = !0;
+               status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL);
+               if (status < 0) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Failed to submit read-control"
+                                  " URB status=%d",status);
+                       hdw->ctl_read_pend_flag = 0;
+                       goto done;
+               }
+       }
+
+       /* Start timer */
+       add_timer(&timer);
+
+       /* Now wait for all I/O to complete */
+       hdw->cmd_debug_state = 4;
+       while (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) {
+               wait_for_completion(&hdw->ctl_done);
+       }
+       hdw->cmd_debug_state = 5;
+
+       /* Stop timer */
+       del_timer_sync(&timer);
+
+       hdw->cmd_debug_state = 6;
+       status = 0;
+
+       if (hdw->ctl_timeout_flag) {
+               status = -ETIMEDOUT;
+               if (!probe_fl) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "Timed out control-write");
+               }
+               goto done;
+       }
+
+       if (write_len) {
+               /* Validate results of write request */
+               if ((hdw->ctl_write_urb->status != 0) &&
+                   (hdw->ctl_write_urb->status != -ENOENT) &&
+                   (hdw->ctl_write_urb->status != -ESHUTDOWN) &&
+                   (hdw->ctl_write_urb->status != -ECONNRESET)) {
+                       /* USB subsystem is reporting some kind of failure
+                          on the write */
+                       status = hdw->ctl_write_urb->status;
+                       if (!probe_fl) {
+                               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                          "control-write URB failure,"
+                                          " status=%d",
+                                          status);
+                       }
+                       goto done;
+               }
+               if (hdw->ctl_write_urb->actual_length < write_len) {
+                       /* Failed to write enough data */
+                       status = -EIO;
+                       if (!probe_fl) {
+                               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                          "control-write URB short,"
+                                          " expected=%d got=%d",
+                                          write_len,
+                                          hdw->ctl_write_urb->actual_length);
+                       }
+                       goto done;
+               }
+       }
+       if (read_len) {
+               /* Validate results of read request */
+               if ((hdw->ctl_read_urb->status != 0) &&
+                   (hdw->ctl_read_urb->status != -ENOENT) &&
+                   (hdw->ctl_read_urb->status != -ESHUTDOWN) &&
+                   (hdw->ctl_read_urb->status != -ECONNRESET)) {
+                       /* USB subsystem is reporting some kind of failure
+                          on the read */
+                       status = hdw->ctl_read_urb->status;
+                       if (!probe_fl) {
+                               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                          "control-read URB failure,"
+                                          " status=%d",
+                                          status);
+                       }
+                       goto done;
+               }
+               if (hdw->ctl_read_urb->actual_length < read_len) {
+                       /* Failed to read enough data */
+                       status = -EIO;
+                       if (!probe_fl) {
+                               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                          "control-read URB short,"
+                                          " expected=%d got=%d",
+                                          read_len,
+                                          hdw->ctl_read_urb->actual_length);
+                       }
+                       goto done;
+               }
+               /* Transfer retrieved data out from internal buffer */
+               for (idx = 0; idx < read_len; idx++) {
+                       ((unsigned char *)read_data)[idx] =
+                               hdw->ctl_read_buffer[idx];
+               }
+       }
+
+ done:
+
+       hdw->cmd_debug_state = 0;
+       if ((status < 0) && (!probe_fl)) {
+               pvr2_hdw_render_useless_unlocked(hdw);
+       }
+       return status;
+}
+
+
+int pvr2_send_request(struct pvr2_hdw *hdw,
+                     void *write_data,unsigned int write_len,
+                     void *read_data,unsigned int read_len)
+{
+       return pvr2_send_request_ex(hdw,HZ*4,0,
+                                   write_data,write_len,
+                                   read_data,read_len);
+}
+
+int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
+{
+       int ret;
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       hdw->cmd_buffer[0] = 0x04;  /* write register prefix */
+       PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data);
+       hdw->cmd_buffer[5] = 0;
+       hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
+       hdw->cmd_buffer[7] = reg & 0xff;
+
+
+       ret = pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 0);
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+
+int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
+{
+       int ret = 0;
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       hdw->cmd_buffer[0] = 0x05;  /* read register prefix */
+       hdw->cmd_buffer[1] = 0;
+       hdw->cmd_buffer[2] = 0;
+       hdw->cmd_buffer[3] = 0;
+       hdw->cmd_buffer[4] = 0;
+       hdw->cmd_buffer[5] = 0;
+       hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
+       hdw->cmd_buffer[7] = reg & 0xff;
+
+       ret |= pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 4);
+       *data = PVR2_COMPOSE_LE(hdw->cmd_buffer,0);
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+
+int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res)
+{
+       int ret;
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       hdw->cmd_buffer[0] = (data >> 8) & 0xff;
+       hdw->cmd_buffer[1] = data & 0xff;
+
+       ret = pvr2_send_request(hdw, hdw->cmd_buffer, 2, hdw->cmd_buffer, res);
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+
+int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res)
+{
+       int ret;
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       hdw->cmd_buffer[0] = data;
+
+       ret = pvr2_send_request(hdw, hdw->cmd_buffer, 1, hdw->cmd_buffer, res);
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+
+void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
+{
+       if (!hdw->flag_ok) return;
+       pvr2_trace(PVR2_TRACE_INIT,"render_useless");
+       hdw->flag_ok = 0;
+       if (hdw->vid_stream) {
+               pvr2_stream_setup(hdw->vid_stream,0,0,0);
+       }
+       hdw->flag_streaming_enabled = 0;
+       hdw->subsys_enabled_mask = 0;
+}
+
+
+void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
+{
+       LOCK_TAKE(hdw->ctl_lock);
+       pvr2_hdw_render_useless_unlocked(hdw);
+       LOCK_GIVE(hdw->ctl_lock);
+}
+
+
+void pvr2_hdw_device_reset(struct pvr2_hdw *hdw)
+{
+       int ret;
+       pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset...");
+       ret = usb_lock_device_for_reset(hdw->usb_dev,0);
+       if (ret == 1) {
+               ret = usb_reset_device(hdw->usb_dev);
+               usb_unlock_device(hdw->usb_dev);
+       } else {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to lock USB device ret=%d",ret);
+       }
+       if (init_pause_msec) {
+               pvr2_trace(PVR2_TRACE_INFO,
+                          "Waiting %u msec for hardware to settle",
+                          init_pause_msec);
+               msleep(init_pause_msec);
+       }
+
+}
+
+
+void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
+{
+       char da[1];
+       unsigned int pipe;
+       int ret;
+
+       if (!hdw->usb_dev) return;
+
+       pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val);
+
+       da[0] = val ? 0x01 : 0x00;
+
+       /* Write the CPUCS register on the 8051.  The lsb of the register
+          is the reset bit; a 1 asserts reset while a 0 clears it. */
+       pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
+       ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,HZ);
+       if (ret < 0) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "cpureset_assert(%d) error=%d",val,ret);
+               pvr2_hdw_render_useless(hdw);
+       }
+}
+
+
+int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
+{
+       int status;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
+               hdw->flag_ok = !0;
+               hdw->cmd_buffer[0] = 0xdd;
+               status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
+       } while (0); LOCK_GIVE(hdw->ctl_lock);
+       return status;
+}
+
+
+int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
+{
+       int status;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
+               hdw->cmd_buffer[0] = 0xde;
+               status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
+       } while (0); LOCK_GIVE(hdw->ctl_lock);
+       return status;
+}
+
+
+int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
+{
+       if (!hdw->decoder_ctrl) {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Unable to reset decoder: nothing attached");
+               return -ENOTTY;
+       }
+
+       if (!hdw->decoder_ctrl->force_reset) {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Unable to reset decoder: not implemented");
+               return -ENOTTY;
+       }
+
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "Requesting decoder reset");
+       hdw->decoder_ctrl->force_reset(hdw->decoder_ctrl->ctxt);
+       return 0;
+}
+
+
+int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
+{
+       int status;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = (runFl ? 0x36 : 0x37);
+               status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
+       } while (0); LOCK_GIVE(hdw->ctl_lock);
+       if (!status) {
+               hdw->subsys_enabled_mask =
+                       ((hdw->subsys_enabled_mask &
+                         ~(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) |
+                        (runFl ? (1<<PVR2_SUBSYS_B_USBSTREAM_RUN) : 0));
+       }
+       return status;
+}
+
+
+void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
+                            struct pvr2_hdw_debug_info *ptr)
+{
+       ptr->big_lock_held = hdw->big_lock_held;
+       ptr->ctl_lock_held = hdw->ctl_lock_held;
+       ptr->flag_ok = hdw->flag_ok;
+       ptr->flag_disconnected = hdw->flag_disconnected;
+       ptr->flag_init_ok = hdw->flag_init_ok;
+       ptr->flag_streaming_enabled = hdw->flag_streaming_enabled;
+       ptr->subsys_flags = hdw->subsys_enabled_mask;
+       ptr->cmd_debug_state = hdw->cmd_debug_state;
+       ptr->cmd_code = hdw->cmd_debug_code;
+       ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
+       ptr->cmd_debug_read_len = hdw->cmd_debug_read_len;
+       ptr->cmd_debug_timeout = hdw->ctl_timeout_flag;
+       ptr->cmd_debug_write_pend = hdw->ctl_write_pend_flag;
+       ptr->cmd_debug_read_pend = hdw->ctl_read_pend_flag;
+       ptr->cmd_debug_rstatus = hdw->ctl_read_urb->status;
+       ptr->cmd_debug_wstatus = hdw->ctl_read_urb->status;
+}
+
+
+int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
+{
+       return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
+}
+
+
+int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *dp)
+{
+       return pvr2_read_register(hdw,PVR2_GPIO_OUT,dp);
+}
+
+
+int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *dp)
+{
+       return pvr2_read_register(hdw,PVR2_GPIO_IN,dp);
+}
+
+
+int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val)
+{
+       u32 cval,nval;
+       int ret;
+       if (~msk) {
+               ret = pvr2_read_register(hdw,PVR2_GPIO_DIR,&cval);
+               if (ret) return ret;
+               nval = (cval & ~msk) | (val & msk);
+               pvr2_trace(PVR2_TRACE_GPIO,
+                          "GPIO direction changing 0x%x:0x%x"
+                          " from 0x%x to 0x%x",
+                          msk,val,cval,nval);
+       } else {
+               nval = val;
+               pvr2_trace(PVR2_TRACE_GPIO,
+                          "GPIO direction changing to 0x%x",nval);
+       }
+       return pvr2_write_register(hdw,PVR2_GPIO_DIR,nval);
+}
+
+
+int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val)
+{
+       u32 cval,nval;
+       int ret;
+       if (~msk) {
+               ret = pvr2_read_register(hdw,PVR2_GPIO_OUT,&cval);
+               if (ret) return ret;
+               nval = (cval & ~msk) | (val & msk);
+               pvr2_trace(PVR2_TRACE_GPIO,
+                          "GPIO output changing 0x%x:0x%x from 0x%x to 0x%x",
+                          msk,val,cval,nval);
+       } else {
+               nval = val;
+               pvr2_trace(PVR2_TRACE_GPIO,
+                          "GPIO output changing to 0x%x",nval);
+       }
+       return pvr2_write_register(hdw,PVR2_GPIO_OUT,nval);
+}
+
+
+int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
+{
+       int result;
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = 0xeb;
+               result = pvr2_send_request(hdw,
+                                          hdw->cmd_buffer,1,
+                                          hdw->cmd_buffer,1);
+               if (result < 0) break;
+               result = hdw->cmd_buffer[0];
+       } while(0); LOCK_GIVE(hdw->ctl_lock);
+       return result;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
new file mode 100644 (file)
index 0000000..63f5291
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_HDW_H
+#define __PVRUSB2_HDW_H
+
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include "pvrusb2-io.h"
+#include "pvrusb2-ctrl.h"
+
+
+/* Private internal control ids, look these up with
+   pvr2_hdw_get_ctrl_by_id() - these are NOT visible in V4L */
+#define PVR2_CID_STDENUM 1
+#define PVR2_CID_STDCUR 2
+#define PVR2_CID_STDAVAIL 3
+#define PVR2_CID_INPUT 4
+#define PVR2_CID_AUDIOMODE 5
+#define PVR2_CID_FREQUENCY 6
+#define PVR2_CID_HRES 7
+#define PVR2_CID_VRES 8
+
+/* Legal values for the INPUT state variable */
+#define PVR2_CVAL_INPUT_TV 0
+#define PVR2_CVAL_INPUT_SVIDEO 1
+#define PVR2_CVAL_INPUT_COMPOSITE 2
+#define PVR2_CVAL_INPUT_RADIO 3
+
+/* Values that pvr2_hdw_get_signal_status() returns */
+#define PVR2_SIGNAL_OK     0x0001
+#define PVR2_SIGNAL_STEREO 0x0002
+#define PVR2_SIGNAL_SAP    0x0004
+
+
+/* Subsystem definitions - these are various pieces that can be
+   independently stopped / started.  Usually you don't want to mess with
+   this directly (let the driver handle things itself), but it is useful
+   for debugging. */
+#define PVR2_SUBSYS_B_ENC_FIRMWARE        0
+#define PVR2_SUBSYS_B_ENC_CFG             1
+#define PVR2_SUBSYS_B_DIGITIZER_RUN       2
+#define PVR2_SUBSYS_B_USBSTREAM_RUN       3
+#define PVR2_SUBSYS_B_ENC_RUN             4
+
+#define PVR2_SUBSYS_CFG_ALL ( \
+       (1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \
+       (1 << PVR2_SUBSYS_B_ENC_CFG) )
+#define PVR2_SUBSYS_RUN_ALL ( \
+       (1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \
+       (1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \
+       (1 << PVR2_SUBSYS_B_ENC_RUN) )
+#define PVR2_SUBSYS_ALL ( \
+       PVR2_SUBSYS_CFG_ALL | \
+       PVR2_SUBSYS_RUN_ALL )
+
+enum pvr2_config {
+       pvr2_config_empty,
+       pvr2_config_mpeg,
+       pvr2_config_vbi,
+       pvr2_config_radio,
+};
+
+const char *pvr2_config_get_name(enum pvr2_config);
+
+struct pvr2_hdw;
+
+/* Create and return a structure for interacting with the underlying
+   hardware */
+struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+                                const struct usb_device_id *devid);
+
+/* Poll for background activity (if any) */
+void pvr2_hdw_poll(struct pvr2_hdw *);
+
+/* Trigger a poll to take place later at a convenient time */
+void pvr2_hdw_poll_trigger(struct pvr2_hdw *);
+void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *);
+
+/* Register a callback used to trigger a future poll */
+void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *,
+                                void (*func)(void *),
+                                void *data);
+
+/* Get pointer to structure given unit number */
+struct pvr2_hdw *pvr2_hdw_find(int unit_number);
+
+/* Destroy hardware interaction structure */
+void pvr2_hdw_destroy(struct pvr2_hdw *);
+
+/* Set up the structure and attempt to put the device into a usable state.
+   This can be a time-consuming operation, which is why it is not done
+   internally as part of the create() step.  Return value is exactly the
+   same as pvr2_hdw_init_ok(). */
+int pvr2_hdw_setup(struct pvr2_hdw *);
+
+/* Initialization succeeded */
+int pvr2_hdw_init_ok(struct pvr2_hdw *);
+
+/* Return true if in the ready (normal) state */
+int pvr2_hdw_dev_ok(struct pvr2_hdw *);
+
+/* Return small integer number [1..N] for logical instance number of this
+   device.  This is useful for indexing array-valued module parameters. */
+int pvr2_hdw_get_unit_number(struct pvr2_hdw *);
+
+/* Get pointer to underlying USB device */
+struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *);
+
+/* Retrieve serial number of device */
+unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *);
+
+/* Called when hardware has been unplugged */
+void pvr2_hdw_disconnect(struct pvr2_hdw *);
+
+/* Get the number of defined controls */
+unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *);
+
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *,unsigned int);
+
+/* Retrieve a control handle given its internal ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *,unsigned int);
+
+/* Retrieve a control handle given its V4L ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *,unsigned int ctl_id);
+
+/* Retrieve a control handle given its immediate predecessor V4L ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *,
+                                           unsigned int ctl_id);
+
+/* Commit all control changes made up to this point */
+int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
+
+/* Return name for this driver instance */
+const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
+
+/* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */
+unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *);
+
+/* Query device and see if it thinks it is on a high-speed USB link */
+int pvr2_hdw_is_hsm(struct pvr2_hdw *);
+
+/* Turn streaming on/off */
+int pvr2_hdw_set_streaming(struct pvr2_hdw *,int);
+
+/* Find out if streaming is on */
+int pvr2_hdw_get_streaming(struct pvr2_hdw *);
+
+/* Configure the type of stream to generate */
+int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config);
+
+/* Get handle to video output stream */
+struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
+
+/* Emit a video standard struct */
+int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
+                              unsigned int idx);
+
+/* Enable / disable various pieces of hardware.  Items to change are
+   identified by bit positions within msk, and new state for each item is
+   identified by corresponding bit positions within val. */
+void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
+                            unsigned long msk,unsigned long val);
+
+/* Shortcut for pvr2_hdw_subsys_bit_chg(hdw,msk,msk) */
+void pvr2_hdw_subsys_bit_set(struct pvr2_hdw *hdw,unsigned long msk);
+
+/* Shortcut for pvr2_hdw_subsys_bit_chg(hdw,msk,0) */
+void pvr2_hdw_subsys_bit_clr(struct pvr2_hdw *hdw,unsigned long msk);
+
+/* Retrieve mask indicating which pieces of hardware are currently enabled
+   / configured. */
+unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *);
+
+/* Adjust mask of what get shut down when streaming is stopped.  This is a
+   debugging aid. */
+void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
+                                   unsigned long msk,unsigned long val);
+
+/* Retrieve mask indicating which pieces of hardware are disabled when
+   streaming is turned off. */
+unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
+
+
+/* Enable / disable retrieval of CPU firmware.  This must be enabled before
+   pvr2_hdw_cpufw_get() will function.  Note that doing this may prevent
+   the device from running (and leaving this mode may imply a device
+   reset). */
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag);
+
+/* Return true if we're in a mode for retrieval CPU firmware */
+int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
+
+/* Retrieve a piece of the CPU's firmware at the given offset.  Return
+   value is the number of bytes retrieved or zero if we're past the end or
+   an error otherwise (e.g. if firmware retrieval is not enabled). */
+int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs,
+                      char *buf,unsigned int cnt);
+
+/* Retrieve previously stored v4l minor device number */
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *);
+
+/* Store the v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
+
+
+/* The following entry points are all lower level things you normally don't
+   want to worry about. */
+
+/* Attempt to recover from a USB foul-up (in practice I find that if you
+   have to do this, then it's already too late). */
+void pvr2_reset_ctl_endpoints(struct pvr2_hdw *hdw);
+
+/* Issue a command and get a response from the device.  LOTS of higher
+   level stuff is built on this. */
+int pvr2_send_request(struct pvr2_hdw *,
+                     void *write_ptr,unsigned int write_len,
+                     void *read_ptr,unsigned int read_len);
+
+/* Issue a command and get a response from the device.  This extended
+   version includes a probe flag (which if set means that device errors
+   should not be logged or treated as fatal) and a timeout in jiffies.
+   This can be used to non-lethally probe the health of endpoint 1. */
+int pvr2_send_request_ex(struct pvr2_hdw *,unsigned int timeout,int probe_fl,
+                        void *write_ptr,unsigned int write_len,
+                        void *read_ptr,unsigned int read_len);
+
+/* Slightly higher level device communication functions. */
+int pvr2_write_register(struct pvr2_hdw *, u16, u32);
+int pvr2_read_register(struct pvr2_hdw *, u16, u32 *);
+int pvr2_write_u16(struct pvr2_hdw *, u16, int);
+int pvr2_write_u8(struct pvr2_hdw *, u8, int);
+
+/* Call if for any reason we can't talk to the hardware anymore - this will
+   cause the driver to stop flailing on the device. */
+void pvr2_hdw_render_useless(struct pvr2_hdw *);
+void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *);
+
+/* Set / clear 8051's reset bit */
+void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int);
+
+/* Execute a USB-commanded device reset */
+void pvr2_hdw_device_reset(struct pvr2_hdw *);
+
+/* Execute hard reset command (after this point it's likely that the
+   encoder will have to be reconfigured).  This also clears the "useless"
+   state. */
+int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *);
+
+/* Execute simple reset command */
+int pvr2_hdw_cmd_powerup(struct pvr2_hdw *);
+
+/* Order decoder to reset */
+int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *);
+
+/* Stop / start video stream transport */
+int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
+
+/* Find I2C address of eeprom */
+int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *);
+
+/* Direct manipulation of GPIO bits */
+int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *);
+int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *);
+int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *);
+int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val);
+int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val);
+
+/* This data structure is specifically for the next function... */
+struct pvr2_hdw_debug_info {
+       int big_lock_held;
+       int ctl_lock_held;
+       int flag_ok;
+       int flag_disconnected;
+       int flag_init_ok;
+       int flag_streaming_enabled;
+       unsigned long subsys_flags;
+       int cmd_debug_state;
+       int cmd_debug_write_len;
+       int cmd_debug_read_len;
+       int cmd_debug_write_pend;
+       int cmd_debug_read_pend;
+       int cmd_debug_timeout;
+       int cmd_debug_rstatus;
+       int cmd_debug_wstatus;
+       unsigned char cmd_code;
+};
+
+/* Non-intrusively retrieve internal state info - this is useful for
+   diagnosing lockups.  Note that this operation is completed without any
+   kind of locking and so it is not atomic and may yield inconsistent
+   results.  This is *purely* a debugging aid. */
+void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
+                            struct pvr2_hdw_debug_info *);
+
+/* Cause modules to log their state once */
+void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
+
+/* Cause encoder firmware to be uploaded into the device.  This is normally
+   done autonomously, but the interface is exported here because it is also
+   a debugging aid. */
+int pvr2_upload_firmware2(struct pvr2_hdw *hdw);
+
+/* List of device types that we can match */
+extern struct usb_device_id pvr2_device_table[];
+
+#endif /* __PVRUSB2_HDW_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
new file mode 100644 (file)
index 0000000..1dd4f62
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 "pvrusb2-i2c-core.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+#include "pvrusb2-audio.h"
+#include "pvrusb2-tuner.h"
+#include "pvrusb2-demod.h"
+#include "pvrusb2-video-v4l.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-wm8775.h"
+#endif
+
+#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
+
+#define OP_STANDARD 0
+#define OP_BCSH 1
+#define OP_VOLUME 2
+#define OP_FREQ 3
+#define OP_AUDIORATE 4
+#define OP_SIZE 5
+#define OP_LOG 6
+
+static const struct pvr2_i2c_op * const ops[] = {
+       [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
+       [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
+       [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
+       [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
+       [OP_SIZE] = &pvr2_i2c_op_v4l2_size,
+       [OP_LOG] = &pvr2_i2c_op_v4l2_log,
+};
+
+void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+       int id;
+       id = cp->client->driver->id;
+       cp->ctl_mask = ((1 << OP_STANDARD) |
+                       (1 << OP_BCSH) |
+                       (1 << OP_VOLUME) |
+                       (1 << OP_FREQ) |
+                       (1 << OP_SIZE) |
+                       (1 << OP_LOG));
+
+       if (id == I2C_DRIVERID_MSP3400) {
+               if (pvr2_i2c_msp3400_setup(hdw,cp)) {
+                       return;
+               }
+       }
+       if (id == I2C_DRIVERID_TUNER) {
+               if (pvr2_i2c_tuner_setup(hdw,cp)) {
+                       return;
+               }
+       }
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       if (id == I2C_DRIVERID_CX25840) {
+               if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) {
+                       return;
+               }
+       }
+       if (id == I2C_DRIVERID_WM8775) {
+               if (pvr2_i2c_wm8775_setup(hdw,cp)) {
+                       return;
+               }
+       }
+#endif
+       if (id == I2C_DRIVERID_SAA711X) {
+               if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) {
+                       return;
+               }
+       }
+       if (id == I2C_DRIVERID_TDA9887) {
+               if (pvr2_i2c_demod_setup(hdw,cp)) {
+                       return;
+               }
+       }
+}
+
+
+const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx)
+{
+       if (idx >= sizeof(ops)/sizeof(ops[0])) return 0;
+       return ops[idx];
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
new file mode 100644 (file)
index 0000000..9f81aff
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-i2c-cmd-v4l2.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+
+
+static void set_standard(struct pvr2_hdw *hdw)
+{
+       v4l2_std_id vs;
+       vs = hdw->std_mask_cur;
+       pvr2_trace(PVR2_TRACE_CHIPS,
+                  "i2c v4l2 set_standard(0x%llx)",(__u64)vs);
+
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+}
+
+
+static int check_standard(struct pvr2_hdw *hdw)
+{
+       return hdw->std_dirty != 0;
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard = {
+       .check = check_standard,
+       .update = set_standard,
+       .name = "v4l2_standard",
+};
+
+
+static void set_bcsh(struct pvr2_hdw *hdw)
+{
+       struct v4l2_control ctrl;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_bcsh"
+                  " b=%d c=%d s=%d h=%d",
+                  hdw->brightness_val,hdw->contrast_val,
+                  hdw->saturation_val,hdw->hue_val);
+       memset(&ctrl,0,sizeof(ctrl));
+       ctrl.id = V4L2_CID_BRIGHTNESS;
+       ctrl.value = hdw->brightness_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_CONTRAST;
+       ctrl.value = hdw->contrast_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_SATURATION;
+       ctrl.value = hdw->saturation_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_HUE;
+       ctrl.value = hdw->hue_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+}
+
+
+static int check_bcsh(struct pvr2_hdw *hdw)
+{
+       return (hdw->brightness_dirty ||
+               hdw->contrast_dirty ||
+               hdw->saturation_dirty ||
+               hdw->hue_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh = {
+       .check = check_bcsh,
+       .update = set_bcsh,
+       .name = "v4l2_bcsh",
+};
+
+
+static void set_volume(struct pvr2_hdw *hdw)
+{
+       struct v4l2_control ctrl;
+       pvr2_trace(PVR2_TRACE_CHIPS,
+                  "i2c v4l2 set_volume"
+                  "(vol=%d bal=%d bas=%d treb=%d mute=%d)",
+                  hdw->volume_val,
+                  hdw->balance_val,
+                  hdw->bass_val,
+                  hdw->treble_val,
+                  hdw->mute_val);
+       memset(&ctrl,0,sizeof(ctrl));
+       ctrl.id = V4L2_CID_AUDIO_MUTE;
+       ctrl.value = hdw->mute_val ? 1 : 0;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_AUDIO_VOLUME;
+       ctrl.value = hdw->volume_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_AUDIO_BALANCE;
+       ctrl.value = hdw->balance_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_AUDIO_BASS;
+       ctrl.value = hdw->bass_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+       ctrl.id = V4L2_CID_AUDIO_TREBLE;
+       ctrl.value = hdw->treble_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+}
+
+
+static int check_volume(struct pvr2_hdw *hdw)
+{
+       return (hdw->volume_dirty ||
+               hdw->balance_dirty ||
+               hdw->bass_dirty ||
+               hdw->treble_dirty ||
+               hdw->mute_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
+       .check = check_volume,
+       .update = set_volume,
+       .name = "v4l2_volume",
+};
+
+
+static void set_frequency(struct pvr2_hdw *hdw)
+{
+       unsigned long fv;
+       struct v4l2_frequency freq;
+       fv = hdw->freqVal;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
+       memset(&freq,0,sizeof(freq));
+       freq.frequency = fv / 62500;
+       freq.tuner = 0;
+       freq.type = V4L2_TUNER_ANALOG_TV;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq);
+}
+
+
+static int check_frequency(struct pvr2_hdw *hdw)
+{
+       return hdw->freqDirty != 0;
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency = {
+       .check = check_frequency,
+       .update = set_frequency,
+       .name = "v4l2_freq",
+};
+
+
+static void set_size(struct pvr2_hdw *hdw)
+{
+       struct v4l2_format fmt;
+
+       memset(&fmt,0,sizeof(fmt));
+
+       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt.fmt.pix.width = hdw->res_hor_val;
+       fmt.fmt.pix.height = hdw->res_ver_val;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_size(%dx%d)",
+                          fmt.fmt.pix.width,fmt.fmt.pix.height);
+
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_FMT,&fmt);
+}
+
+
+static int check_size(struct pvr2_hdw *hdw)
+{
+       return (hdw->res_hor_dirty || hdw->res_ver_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = {
+       .check = check_size,
+       .update = set_size,
+       .name = "v4l2_size",
+};
+
+
+static void do_log(struct pvr2_hdw *hdw)
+{
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()");
+       pvr2_i2c_core_cmd(hdw,VIDIOC_LOG_STATUS,0);
+
+}
+
+
+static int check_log(struct pvr2_hdw *hdw)
+{
+       return hdw->log_requested != 0;
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log = {
+       .check = check_log,
+       .update = do_log,
+       .name = "v4l2_log",
+};
+
+
+void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
+{
+       pvr2_i2c_client_cmd(cp,
+                           (fl ? VIDIOC_STREAMON : VIDIOC_STREAMOFF),0);
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
new file mode 100644 (file)
index 0000000..ecabddb
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_CMD_V4L2_H
+#define __PVRUSB2_CMD_V4L2_H
+
+#include "pvrusb2-i2c-core.h"
+
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
+
+void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+
+#endif /* __PVRUSB2_CMD_V4L2_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
new file mode 100644 (file)
index 0000000..c8d0bde
--- /dev/null
@@ -0,0 +1,937 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 "pvrusb2-i2c-core.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+
+#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
+
+/*
+
+  This module attempts to implement a compliant I2C adapter for the pvrusb2
+  device.  By doing this we can then make use of existing functionality in
+  V4L (e.g. tuner.c) rather than rolling our own.
+
+*/
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
+static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
+                         u8 i2c_addr,      /* I2C address we're talking to */
+                         u8 *data,         /* Data to write */
+                         u16 length)       /* Size of data to write */
+{
+       /* Return value - default 0 means success */
+       int ret;
+
+
+       if (!data) length = 0;
+       if (length > (sizeof(hdw->cmd_buffer) - 3)) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Killing an I2C write to %u that is too large"
+                          " (desired=%u limit=%u)",
+                          i2c_addr,
+                          length,(unsigned int)(sizeof(hdw->cmd_buffer) - 3));
+               return -ENOTSUPP;
+       }
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       /* Clear the command buffer (likely to be paranoia) */
+       memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
+
+       /* Set up command buffer for an I2C write */
+       hdw->cmd_buffer[0] = 0x08;      /* write prefix */
+       hdw->cmd_buffer[1] = i2c_addr;  /* i2c addr of chip */
+       hdw->cmd_buffer[2] = length;    /* length of what follows */
+       if (length) memcpy(hdw->cmd_buffer + 3, data, length);
+
+       /* Do the operation */
+       ret = pvr2_send_request(hdw,
+                               hdw->cmd_buffer,
+                               length + 3,
+                               hdw->cmd_buffer,
+                               1);
+       if (!ret) {
+               if (hdw->cmd_buffer[0] != 8) {
+                       ret = -EIO;
+                       if (hdw->cmd_buffer[0] != 7) {
+                               trace_i2c("unexpected status"
+                                         " from i2_write[%d]: %d",
+                                         i2c_addr,hdw->cmd_buffer[0]);
+                       }
+               }
+       }
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
+                        u8 i2c_addr,       /* I2C address we're talking to */
+                        u8 *data,          /* Data to write */
+                        u16 dlen,          /* Size of data to write */
+                        u8 *res,           /* Where to put data we read */
+                        u16 rlen)          /* Amount of data to read */
+{
+       /* Return value - default 0 means success */
+       int ret;
+
+
+       if (!data) dlen = 0;
+       if (dlen > (sizeof(hdw->cmd_buffer) - 4)) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Killing an I2C read to %u that has wlen too large"
+                          " (desired=%u limit=%u)",
+                          i2c_addr,
+                          dlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 4));
+               return -ENOTSUPP;
+       }
+       if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Killing an I2C read to %u that has rlen too large"
+                          " (desired=%u limit=%u)",
+                          i2c_addr,
+                          rlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 1));
+               return -ENOTSUPP;
+       }
+
+       LOCK_TAKE(hdw->ctl_lock);
+
+       /* Clear the command buffer (likely to be paranoia) */
+       memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
+
+       /* Set up command buffer for an I2C write followed by a read */
+       hdw->cmd_buffer[0] = 0x09;  /* read prefix */
+       hdw->cmd_buffer[1] = dlen;  /* arg length */
+       hdw->cmd_buffer[2] = rlen;  /* answer length. Device will send one
+                                      more byte (status). */
+       hdw->cmd_buffer[3] = i2c_addr;  /* i2c addr of chip */
+       if (dlen) memcpy(hdw->cmd_buffer + 4, data, dlen);
+
+       /* Do the operation */
+       ret = pvr2_send_request(hdw,
+                               hdw->cmd_buffer,
+                               4 + dlen,
+                               hdw->cmd_buffer,
+                               rlen + 1);
+       if (!ret) {
+               if (hdw->cmd_buffer[0] != 8) {
+                       ret = -EIO;
+                       if (hdw->cmd_buffer[0] != 7) {
+                               trace_i2c("unexpected status"
+                                         " from i2_read[%d]: %d",
+                                         i2c_addr,hdw->cmd_buffer[0]);
+                       }
+               }
+       }
+
+       /* Copy back the result */
+       if (res && rlen) {
+               if (ret) {
+                       /* Error, just blank out the return buffer */
+                       memset(res, 0, rlen);
+               } else {
+                       memcpy(res, hdw->cmd_buffer + 1, rlen);
+               }
+       }
+
+       LOCK_GIVE(hdw->ctl_lock);
+
+       return ret;
+}
+
+/* This is the common low level entry point for doing I2C operations to the
+   hardware. */
+int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
+                     u8 i2c_addr,
+                     u8 *wdata,
+                     u16 wlen,
+                     u8 *rdata,
+                     u16 rlen)
+{
+       if (!rdata) rlen = 0;
+       if (!wdata) wlen = 0;
+       if (rlen || !wlen) {
+               return pvr2_i2c_read(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+       } else {
+               return pvr2_i2c_write(hdw,i2c_addr,wdata,wlen);
+       }
+}
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+
+/* This is a special entry point that is entered if an I2C operation is
+   attempted to a wm8775 chip on model 24xxx hardware.  Autodetect of this
+   part doesn't work, but we know it is really there.  So let's look for
+   the autodetect attempt and just return success if we see that. */
+static int i2c_hack_wm8775(struct pvr2_hdw *hdw,
+                          u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+       if (!(rlen || wlen)) {
+               // This is a probe attempt.  Just let it succeed.
+               return 0;
+       }
+       return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+}
+
+/* This is a special entry point that is entered if an I2C operation is
+   attempted to a cx25840 chip on model 24xxx hardware.  This chip can
+   sometimes wedge itself.  Worse still, when this happens msp3400 can
+   falsely detect this part and then the system gets hosed up after msp3400
+   gets confused and dies.  What we want to do here is try to keep msp3400
+   away and also try to notice if the chip is wedged and send a warning to
+   the system log. */
+static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
+                           u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+       int ret;
+       unsigned int subaddr;
+       u8 wbuf[2];
+       int state = hdw->i2c_cx25840_hack_state;
+
+       if (!(rlen || wlen)) {
+               // Probe attempt - always just succeed and don't bother the
+               // hardware (this helps to make the state machine further
+               // down somewhat easier).
+               return 0;
+       }
+
+       if (state == 3) {
+               return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+       }
+
+       /* We're looking for the exact pattern where the revision register
+          is being read.  The cx25840 module will always look at the
+          revision register first.  Any other pattern of access therefore
+          has to be a probe attempt from somebody else so we'll reject it.
+          Normally we could just let each client just probe the part
+          anyway, but when the cx25840 is wedged, msp3400 will get a false
+          positive and that just screws things up... */
+
+       if (wlen == 0) {
+               switch (state) {
+               case 1: subaddr = 0x0100; break;
+               case 2: subaddr = 0x0101; break;
+               default: goto fail;
+               }
+       } else if (wlen == 2) {
+               subaddr = (wdata[0] << 8) | wdata[1];
+               switch (subaddr) {
+               case 0x0100: state = 1; break;
+               case 0x0101: state = 2; break;
+               default: goto fail;
+               }
+       } else {
+               goto fail;
+       }
+       if (!rlen) goto success;
+       state = 0;
+       if (rlen != 1) goto fail;
+
+       /* If we get to here then we have a legitimate read for one of the
+          two revision bytes, so pass it through. */
+       wbuf[0] = subaddr >> 8;
+       wbuf[1] = subaddr;
+       ret = pvr2_i2c_basic_op(hdw,i2c_addr,wbuf,2,rdata,rlen);
+
+       if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "WARNING: Detected a wedged cx25840 chip;"
+                          " the device will not work.");
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "WARNING: Try power cycling the pvrusb2 device.");
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "WARNING: Disabling further access to the device"
+                          " to prevent other foul-ups.");
+               // This blocks all further communication with the part.
+               hdw->i2c_func[0x44] = 0;
+               pvr2_hdw_render_useless(hdw);
+               goto fail;
+       }
+
+       /* Success! */
+       pvr2_trace(PVR2_TRACE_CHIPS,"cx25840 appears to be OK.");
+       state = 3;
+
+ success:
+       hdw->i2c_cx25840_hack_state = state;
+       return 0;
+
+ fail:
+       hdw->i2c_cx25840_hack_state = state;
+       return -EIO;
+}
+
+#endif /* CONFIG_VIDEO_PVRUSB2_24XXX */
+
+/* This is a very, very limited I2C adapter implementation.  We can only
+   support what we actually know will work on the device... */
+static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
+                        struct i2c_msg msgs[],
+                        int num)
+{
+       int ret = -ENOTSUPP;
+       pvr2_i2c_func funcp = 0;
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data);
+
+       if (!num) {
+               ret = -EINVAL;
+               goto done;
+       }
+       if ((msgs[0].flags & I2C_M_NOSTART)) {
+               trace_i2c("i2c refusing I2C_M_NOSTART");
+               goto done;
+       }
+       if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
+               funcp = hdw->i2c_func[msgs[0].addr];
+       }
+       if (!funcp) {
+               ret = -EIO;
+               goto done;
+       }
+
+       if (num == 1) {
+               if (msgs[0].flags & I2C_M_RD) {
+                       /* Simple read */
+                       u16 tcnt,bcnt,offs;
+                       if (!msgs[0].len) {
+                               /* Length == 0 read.  This is a probe. */
+                               if (funcp(hdw,msgs[0].addr,0,0,0,0)) {
+                                       ret = -EIO;
+                                       goto done;
+                               }
+                               ret = 1;
+                               goto done;
+                       }
+                       /* If the read is short enough we'll do the whole
+                          thing atomically.  Otherwise we have no choice
+                          but to break apart the reads. */
+                       tcnt = msgs[0].len;
+                       offs = 0;
+                       while (tcnt) {
+                               bcnt = tcnt;
+                               if (bcnt > sizeof(hdw->cmd_buffer)-1) {
+                                       bcnt = sizeof(hdw->cmd_buffer)-1;
+                               }
+                               if (funcp(hdw,msgs[0].addr,0,0,
+                                         msgs[0].buf+offs,bcnt)) {
+                                       ret = -EIO;
+                                       goto done;
+                               }
+                               offs += bcnt;
+                               tcnt -= bcnt;
+                       }
+                       ret = 1;
+                       goto done;
+               } else {
+                       /* Simple write */
+                       ret = 1;
+                       if (funcp(hdw,msgs[0].addr,
+                                 msgs[0].buf,msgs[0].len,0,0)) {
+                               ret = -EIO;
+                       }
+                       goto done;
+               }
+       } else if (num == 2) {
+               if (msgs[0].addr != msgs[1].addr) {
+                       trace_i2c("i2c refusing 2 phase transfer with"
+                                 " conflicting target addresses");
+                       ret = -ENOTSUPP;
+                       goto done;
+               }
+               if ((!((msgs[0].flags & I2C_M_RD))) &&
+                   (msgs[1].flags & I2C_M_RD)) {
+                       u16 tcnt,bcnt,wcnt,offs;
+                       /* Write followed by atomic read.  If the read
+                          portion is short enough we'll do the whole thing
+                          atomically.  Otherwise we have no choice but to
+                          break apart the reads. */
+                       tcnt = msgs[1].len;
+                       wcnt = msgs[0].len;
+                       offs = 0;
+                       while (tcnt || wcnt) {
+                               bcnt = tcnt;
+                               if (bcnt > sizeof(hdw->cmd_buffer)-1) {
+                                       bcnt = sizeof(hdw->cmd_buffer)-1;
+                               }
+                               if (funcp(hdw,msgs[0].addr,
+                                         msgs[0].buf,wcnt,
+                                         msgs[1].buf+offs,bcnt)) {
+                                       ret = -EIO;
+                                       goto done;
+                               }
+                               offs += bcnt;
+                               tcnt -= bcnt;
+                               wcnt = 0;
+                       }
+                       ret = 2;
+                       goto done;
+               } else {
+                       trace_i2c("i2c refusing complex transfer"
+                                 " read0=%d read1=%d",
+                                 (msgs[0].flags & I2C_M_RD),
+                                 (msgs[1].flags & I2C_M_RD));
+               }
+       } else {
+               trace_i2c("i2c refusing %d phase transfer",num);
+       }
+
+ done:
+       if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) {
+               unsigned int idx,offs,cnt;
+               for (idx = 0; idx < num; idx++) {
+                       cnt = msgs[idx].len;
+                       printk(KERN_INFO
+                              "pvrusb2 i2c xfer %u/%u:"
+                              " addr=0x%x len=%d %s%s",
+                              idx+1,num,
+                              msgs[idx].addr,
+                              cnt,
+                              (msgs[idx].flags & I2C_M_RD ?
+                               "read" : "write"),
+                              (msgs[idx].flags & I2C_M_NOSTART ?
+                               " nostart" : ""));
+                       if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
+                               if (cnt > 8) cnt = 8;
+                               printk(" [");
+                               for (offs = 0; offs < (cnt>8?8:cnt); offs++) {
+                                       if (offs) printk(" ");
+                                       printk("%02x",msgs[idx].buf[offs]);
+                               }
+                               if (offs < cnt) printk(" ...");
+                               printk("]");
+                       }
+                       if (idx+1 == num) {
+                               printk(" result=%d",ret);
+                       }
+                       printk("\n");
+               }
+               if (!num) {
+                       printk(KERN_INFO
+                              "pvrusb2 i2c xfer null transfer result=%d\n",
+                              ret);
+               }
+       }
+       return ret;
+}
+
+static int pvr2_i2c_control(struct i2c_adapter *adapter,
+                           unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static int pvr2_i2c_core_singleton(struct i2c_client *cp,
+                                  unsigned int cmd,void *arg)
+{
+       int stat;
+       if (!cp) return -EINVAL;
+       if (!(cp->driver)) return -EINVAL;
+       if (!(cp->driver->command)) return -EINVAL;
+       if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
+       stat = cp->driver->command(cp,cmd,arg);
+       module_put(cp->driver->driver.owner);
+       return stat;
+}
+
+int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
+{
+       int stat;
+       if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+               char buf[100];
+               unsigned int cnt;
+               cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+                                              buf,sizeof(buf));
+               pvr2_trace(PVR2_TRACE_I2C_CMD,
+                          "i2c COMMAND (code=%u 0x%x) to %.*s",
+                          cmd,cmd,cnt,buf);
+       }
+       stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
+       if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+               char buf[100];
+               unsigned int cnt;
+               cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+                                              buf,sizeof(buf));
+               pvr2_trace(PVR2_TRACE_I2C_CMD,
+                          "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
+       }
+       return stat;
+}
+
+int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
+{
+       struct list_head *item,*nc;
+       struct pvr2_i2c_client *cp;
+       int stat = -EINVAL;
+
+       if (!hdw) return stat;
+
+       mutex_lock(&hdw->i2c_list_lock);
+       list_for_each_safe(item,nc,&hdw->i2c_clients) {
+               cp = list_entry(item,struct pvr2_i2c_client,list);
+               if (!cp->recv_enable) continue;
+               mutex_unlock(&hdw->i2c_list_lock);
+               stat = pvr2_i2c_client_cmd(cp,cmd,arg);
+               mutex_lock(&hdw->i2c_list_lock);
+       }
+       mutex_unlock(&hdw->i2c_list_lock);
+       return stat;
+}
+
+
+static int handler_check(struct pvr2_i2c_client *cp)
+{
+       struct pvr2_i2c_handler *hp = cp->handler;
+       if (!hp) return 0;
+       if (!hp->func_table->check) return 0;
+       return hp->func_table->check(hp->func_data) != 0;
+}
+
+#define BUFSIZE 500
+
+void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
+{
+       unsigned long msk;
+       unsigned int idx;
+       struct list_head *item,*nc;
+       struct pvr2_i2c_client *cp;
+
+       if (!hdw->i2c_linked) return;
+       if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
+               return;
+       }
+       mutex_lock(&hdw->i2c_list_lock); do {
+               pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
+                       /* One or more I2C clients have attached since we
+                          last synced.  So scan the list and identify the
+                          new clients. */
+                       char *buf;
+                       unsigned int cnt;
+                       unsigned long amask = 0;
+                       buf = kmalloc(BUFSIZE,GFP_KERNEL);
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
+                       list_for_each(item,&hdw->i2c_clients) {
+                               cp = list_entry(item,struct pvr2_i2c_client,
+                                               list);
+                               if (!cp->detected_flag) {
+                                       cp->ctl_mask = 0;
+                                       pvr2_i2c_probe(hdw,cp);
+                                       cp->detected_flag = !0;
+                                       msk = cp->ctl_mask;
+                                       cnt = 0;
+                                       if (buf) {
+                                               cnt = pvr2_i2c_client_describe(
+                                                       cp,
+                                                       PVR2_I2C_DETAIL_ALL,
+                                                       buf,BUFSIZE);
+                                       }
+                                       trace_i2c("Probed: %.*s",cnt,buf);
+                                       if (handler_check(cp)) {
+                                               hdw->i2c_pend_types |=
+                                                       PVR2_I2C_PEND_CLIENT;
+                                       }
+                                       cp->pend_mask = msk;
+                                       hdw->i2c_pend_mask |= msk;
+                                       hdw->i2c_pend_types |=
+                                               PVR2_I2C_PEND_REFRESH;
+                               }
+                               amask |= cp->ctl_mask;
+                       }
+                       hdw->i2c_active_mask = amask;
+                       if (buf) kfree(buf);
+               }
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
+                       /* Need to do one or more global updates.  Arrange
+                          for this to happen. */
+                       unsigned long m2;
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,
+                                  "i2c: PEND_STALE (0x%lx)",
+                                  hdw->i2c_stale_mask);
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
+                       list_for_each(item,&hdw->i2c_clients) {
+                               cp = list_entry(item,struct pvr2_i2c_client,
+                                               list);
+                               m2 = hdw->i2c_stale_mask;
+                               m2 &= cp->ctl_mask;
+                               m2 &= ~cp->pend_mask;
+                               if (m2) {
+                                       pvr2_trace(PVR2_TRACE_I2C_CORE,
+                                                  "i2c: cp=%p setting 0x%lx",
+                                                  cp,m2);
+                                       cp->pend_mask |= m2;
+                               }
+                       }
+                       hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
+                       hdw->i2c_stale_mask = 0;
+                       hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
+               }
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
+                       /* One or more client handlers are asking for an
+                          update.  Run through the list of known clients
+                          and update each one. */
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
+                       list_for_each_safe(item,nc,&hdw->i2c_clients) {
+                               cp = list_entry(item,struct pvr2_i2c_client,
+                                               list);
+                               if (!cp->handler) continue;
+                               if (!cp->handler->func_table->update) continue;
+                               pvr2_trace(PVR2_TRACE_I2C_CORE,
+                                          "i2c: cp=%p update",cp);
+                               mutex_unlock(&hdw->i2c_list_lock);
+                               cp->handler->func_table->update(
+                                       cp->handler->func_data);
+                               mutex_lock(&hdw->i2c_list_lock);
+                               /* If client's update function set some
+                                  additional pending bits, account for that
+                                  here. */
+                               if (cp->pend_mask & ~hdw->i2c_pend_mask) {
+                                       hdw->i2c_pend_mask |= cp->pend_mask;
+                                       hdw->i2c_pend_types |=
+                                               PVR2_I2C_PEND_REFRESH;
+                               }
+                       }
+               }
+               if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
+                       const struct pvr2_i2c_op *opf;
+                       unsigned long pm;
+                       /* Some actual updates are pending.  Walk through
+                          each update type and perform it. */
+                       pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
+                                  " (0x%lx)",hdw->i2c_pend_mask);
+                       hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
+                       pm = hdw->i2c_pend_mask;
+                       hdw->i2c_pend_mask = 0;
+                       for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
+                               if (!(pm & msk)) continue;
+                               pm &= ~msk;
+                               list_for_each(item,&hdw->i2c_clients) {
+                                       cp = list_entry(item,
+                                                       struct pvr2_i2c_client,
+                                                       list);
+                                       if (cp->pend_mask & msk) {
+                                               cp->pend_mask &= ~msk;
+                                               cp->recv_enable = !0;
+                                       } else {
+                                               cp->recv_enable = 0;
+                                       }
+                               }
+                               opf = pvr2_i2c_get_op(idx);
+                               if (!opf) continue;
+                               mutex_unlock(&hdw->i2c_list_lock);
+                               opf->update(hdw);
+                               mutex_lock(&hdw->i2c_list_lock);
+                       }
+               }
+               pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
+{
+       unsigned long msk,sm,pm;
+       unsigned int idx;
+       const struct pvr2_i2c_op *opf;
+       struct list_head *item;
+       struct pvr2_i2c_client *cp;
+       unsigned int pt = 0;
+
+       pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
+
+       pm = hdw->i2c_active_mask;
+       sm = 0;
+       for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
+               if (!(msk & pm)) continue;
+               pm &= ~msk;
+               opf = pvr2_i2c_get_op(idx);
+               if (!opf) continue;
+               if (opf->check(hdw)) {
+                       sm |= msk;
+               }
+       }
+       if (sm) pt |= PVR2_I2C_PEND_STALE;
+
+       list_for_each(item,&hdw->i2c_clients) {
+               cp = list_entry(item,struct pvr2_i2c_client,list);
+               if (!handler_check(cp)) continue;
+               pt |= PVR2_I2C_PEND_CLIENT;
+       }
+
+       if (pt) {
+               mutex_lock(&hdw->i2c_list_lock); do {
+                       hdw->i2c_pend_types |= pt;
+                       hdw->i2c_stale_mask |= sm;
+                       hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
+               } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       }
+
+       pvr2_trace(PVR2_TRACE_I2C_CORE,
+                  "i2c: types=0x%x stale=0x%lx pend=0x%lx",
+                  hdw->i2c_pend_types,
+                  hdw->i2c_stale_mask,
+                  hdw->i2c_pend_mask);
+       pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
+
+       return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
+}
+
+unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
+                                     unsigned int detail,
+                                     char *buf,unsigned int maxlen)
+{
+       unsigned int ccnt,bcnt;
+       int spcfl = 0;
+       const struct pvr2_i2c_op *opf;
+
+       ccnt = 0;
+       if (detail & PVR2_I2C_DETAIL_DEBUG) {
+               bcnt = scnprintf(buf,maxlen,
+                                "ctxt=%p ctl_mask=0x%lx",
+                                cp,cp->ctl_mask);
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               spcfl = !0;
+       }
+       bcnt = scnprintf(buf,maxlen,
+                        "%s%s @ 0x%x",
+                        (spcfl ? " " : ""),
+                        cp->client->name,
+                        cp->client->addr);
+       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+       if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
+           cp->handler && cp->handler->func_table->describe) {
+               bcnt = scnprintf(buf,maxlen," (");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               bcnt = cp->handler->func_table->describe(
+                       cp->handler->func_data,buf,maxlen);
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               bcnt = scnprintf(buf,maxlen,")");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+       }
+       if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
+               unsigned int idx;
+               unsigned long msk,sm;
+               int spcfl;
+               bcnt = scnprintf(buf,maxlen," [");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               sm = 0;
+               spcfl = 0;
+               for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
+                       if (!(cp->ctl_mask & msk)) continue;
+                       opf = pvr2_i2c_get_op(idx);
+                       if (opf) {
+                               bcnt = scnprintf(buf,maxlen,"%s%s",
+                                                spcfl ? " " : "",
+                                                opf->name);
+                               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+                               spcfl = !0;
+                       } else {
+                               sm |= msk;
+                       }
+               }
+               if (sm) {
+                       bcnt = scnprintf(buf,maxlen,"%s%lx",
+                                        idx != 0 ? " " : "",sm);
+                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               }
+               bcnt = scnprintf(buf,maxlen,"]");
+               ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+       }
+       return ccnt;
+}
+
+unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
+                            char *buf,unsigned int maxlen)
+{
+       unsigned int ccnt,bcnt;
+       struct list_head *item;
+       struct pvr2_i2c_client *cp;
+       ccnt = 0;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               list_for_each(item,&hdw->i2c_clients) {
+                       cp = list_entry(item,struct pvr2_i2c_client,list);
+                       bcnt = pvr2_i2c_client_describe(
+                               cp,
+                               (PVR2_I2C_DETAIL_HANDLER|
+                                PVR2_I2C_DETAIL_CTLMASK),
+                               buf,maxlen);
+                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+                       bcnt = scnprintf(buf,maxlen,"\n");
+                       ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+               }
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       return ccnt;
+}
+
+static int pvr2_i2c_attach_inform(struct i2c_client *client)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
+       struct pvr2_i2c_client *cp;
+       int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
+       cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+       trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
+                 client->name,
+                 client->addr,cp);
+       if (!cp) return -ENOMEM;
+       memset(cp,0,sizeof(*cp));
+       INIT_LIST_HEAD(&cp->list);
+       cp->client = client;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               list_add_tail(&cp->list,&hdw->i2c_clients);
+               hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       if (fl) pvr2_hdw_poll_trigger_unlocked(hdw);
+       return 0;
+}
+
+static int pvr2_i2c_detach_inform(struct i2c_client *client)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
+       struct pvr2_i2c_client *cp;
+       struct list_head *item,*nc;
+       unsigned long amask = 0;
+       int foundfl = 0;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               list_for_each_safe(item,nc,&hdw->i2c_clients) {
+                       cp = list_entry(item,struct pvr2_i2c_client,list);
+                       if (cp->client == client) {
+                               trace_i2c("pvr2_i2c_detach"
+                                         " [client=%s @ 0x%x ctxt=%p]",
+                                         client->name,
+                                         client->addr,cp);
+                               if (cp->handler &&
+                                   cp->handler->func_table->detach) {
+                                       cp->handler->func_table->detach(
+                                               cp->handler->func_data);
+                               }
+                               list_del(&cp->list);
+                               kfree(cp);
+                               foundfl = !0;
+                               continue;
+                       }
+                       amask |= cp->ctl_mask;
+               }
+               hdw->i2c_active_mask = amask;
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       if (!foundfl) {
+               trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
+                         client->name,
+                         client->addr);
+       }
+       return 0;
+}
+
+static struct i2c_algorithm pvr2_i2c_algo_template = {
+       .master_xfer   = pvr2_i2c_xfer,
+       .algo_control  = pvr2_i2c_control,
+       .functionality = pvr2_i2c_functionality,
+};
+
+static struct i2c_adapter pvr2_i2c_adap_template = {
+       .owner         = THIS_MODULE,
+       .class     = I2C_CLASS_TV_ANALOG,
+       .id            = I2C_HW_B_BT848,
+       .client_register = pvr2_i2c_attach_inform,
+       .client_unregister = pvr2_i2c_detach_inform,
+};
+
+static void do_i2c_scan(struct pvr2_hdw *hdw)
+{
+       struct i2c_msg msg[1];
+       int i,rc;
+       msg[0].addr = 0;
+       msg[0].flags = I2C_M_RD;
+       msg[0].len = 0;
+       msg[0].buf = 0;
+       printk("%s: i2c scan beginning\n",hdw->name);
+       for (i = 0; i < 128; i++) {
+               msg[0].addr = i;
+               rc = i2c_transfer(&hdw->i2c_adap,msg,
+                                 sizeof(msg)/sizeof(msg[0]));
+               if (rc != 1) continue;
+               printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
+       }
+       printk("%s: i2c scan done.\n",hdw->name);
+}
+
+void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
+{
+       unsigned int idx;
+
+       // The default action for all possible I2C addresses is just to do
+       // the transfer normally.
+       for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
+               hdw->i2c_func[idx] = pvr2_i2c_basic_op;
+       }
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+       // If however we're dealing with new hardware, insert some hacks in
+       // the I2C transfer stack to let things work better.
+       if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+               hdw->i2c_func[0x1b] = i2c_hack_wm8775;
+               hdw->i2c_func[0x44] = i2c_hack_cx25840;
+       }
+#endif
+
+       // Configure the adapter and set up everything else related to it.
+       memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
+       memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));
+       strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
+       hdw->i2c_adap.algo = &hdw->i2c_algo;
+       hdw->i2c_adap.algo_data = hdw;
+       hdw->i2c_pend_mask = 0;
+       hdw->i2c_stale_mask = 0;
+       hdw->i2c_active_mask = 0;
+       INIT_LIST_HEAD(&hdw->i2c_clients);
+       mutex_init(&hdw->i2c_list_lock);
+       hdw->i2c_linked = !0;
+       i2c_add_adapter(&hdw->i2c_adap);
+       if (i2c_scan) do_i2c_scan(hdw);
+}
+
+void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
+{
+       if (hdw->i2c_linked) {
+               i2c_del_adapter(&hdw->i2c_adap);
+               hdw->i2c_linked = 0;
+       }
+}
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
new file mode 100644 (file)
index 0000000..e8af5b0
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_I2C_CORE_H
+#define __PVRUSB2_I2C_CORE_H
+
+#include <linux/list.h>
+#include <linux/i2c.h>
+
+struct pvr2_hdw;
+struct pvr2_i2c_client;
+struct pvr2_i2c_handler;
+struct pvr2_i2c_handler_functions;
+struct pvr2_i2c_op;
+struct pvr2_i2c_op_functions;
+
+struct pvr2_i2c_client {
+       struct i2c_client *client;
+       struct pvr2_i2c_handler *handler;
+       struct list_head list;
+       int detected_flag;
+       int recv_enable;
+       unsigned long pend_mask;
+       unsigned long ctl_mask;
+};
+
+struct pvr2_i2c_handler {
+       void *func_data;
+       const struct pvr2_i2c_handler_functions *func_table;
+};
+
+struct pvr2_i2c_handler_functions {
+       void (*detach)(void *);
+       int (*check)(void *);
+       void (*update)(void *);
+       unsigned int (*describe)(void *,char *,unsigned int);
+};
+
+struct pvr2_i2c_op {
+       int (*check)(struct pvr2_hdw *);
+       void (*update)(struct pvr2_hdw *);
+       const char *name;
+};
+
+void pvr2_i2c_core_init(struct pvr2_hdw *);
+void pvr2_i2c_core_done(struct pvr2_hdw *);
+
+int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg);
+int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
+
+int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
+void pvr2_i2c_core_sync(struct pvr2_hdw *);
+unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
+#define PVR2_I2C_DETAIL_DEBUG   0x0001
+#define PVR2_I2C_DETAIL_HANDLER 0x0002
+#define PVR2_I2C_DETAIL_CTLMASK 0x0004
+#define PVR2_I2C_DETAIL_ALL (\
+       PVR2_I2C_DETAIL_DEBUG |\
+       PVR2_I2C_DETAIL_HANDLER |\
+       PVR2_I2C_DETAIL_CTLMASK)
+unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *,
+                                     unsigned int detail_mask,
+                                     char *buf,unsigned int maxlen);
+
+void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
+const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
+
+#endif /* __PVRUSB2_I2C_CORE_H */
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
new file mode 100644 (file)
index 0000000..a984c91
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 "pvrusb2-io.h"
+#include "pvrusb2-debug.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+
+#define BUFFER_SIG 0x47653271
+
+// #define SANITY_CHECK_BUFFERS
+
+
+#ifdef SANITY_CHECK_BUFFERS
+#define BUFFER_CHECK(bp) do { \
+       if ((bp)->signature != BUFFER_SIG) { \
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS, \
+               "Buffer %p is bad at %s:%d", \
+               (bp),__FILE__,__LINE__); \
+               pvr2_buffer_describe(bp,"BadSig"); \
+               BUG(); \
+       } \
+} while (0)
+#else
+#define BUFFER_CHECK(bp) do {} while(0)
+#endif
+
+struct pvr2_stream {
+       /* Buffers queued for reading */
+       struct list_head queued_list;
+       unsigned int q_count;
+       unsigned int q_bcount;
+       /* Buffers with retrieved data */
+       struct list_head ready_list;
+       unsigned int r_count;
+       unsigned int r_bcount;
+       /* Buffers available for use */
+       struct list_head idle_list;
+       unsigned int i_count;
+       unsigned int i_bcount;
+       /* Pointers to all buffers */
+       struct pvr2_buffer **buffers;
+       /* Array size of buffers */
+       unsigned int buffer_slot_count;
+       /* Total buffers actually in circulation */
+       unsigned int buffer_total_count;
+       /* Designed number of buffers to be in circulation */
+       unsigned int buffer_target_count;
+       /* Executed when ready list become non-empty */
+       pvr2_stream_callback callback_func;
+       void *callback_data;
+       /* Context for transfer endpoint */
+       struct usb_device *dev;
+       int endpoint;
+       /* Overhead for mutex enforcement */
+       spinlock_t list_lock;
+       struct mutex mutex;
+       /* Tracking state for tolerating errors */
+       unsigned int fail_count;
+       unsigned int fail_tolerance;
+};
+
+struct pvr2_buffer {
+       int id;
+       int signature;
+       enum pvr2_buffer_state state;
+       void *ptr;               /* Pointer to storage area */
+       unsigned int max_count;  /* Size of storage area */
+       unsigned int used_count; /* Amount of valid data in storage area */
+       int status;              /* Transfer result status */
+       struct pvr2_stream *stream;
+       struct list_head list_overhead;
+       struct urb *purb;
+};
+
+const char *pvr2_buffer_state_decode(enum pvr2_buffer_state st)
+{
+       switch (st) {
+       case pvr2_buffer_state_none: return "none";
+       case pvr2_buffer_state_idle: return "idle";
+       case pvr2_buffer_state_queued: return "queued";
+       case pvr2_buffer_state_ready: return "ready";
+       }
+       return "unknown";
+}
+
+void pvr2_buffer_describe(struct pvr2_buffer *bp,const char *msg)
+{
+       pvr2_trace(PVR2_TRACE_INFO,
+                  "buffer%s%s %p state=%s id=%d status=%d"
+                  " stream=%p purb=%p sig=0x%x",
+                  (msg ? " " : ""),
+                  (msg ? msg : ""),
+                  bp,
+                  (bp ? pvr2_buffer_state_decode(bp->state) : "(invalid)"),
+                  (bp ? bp->id : 0),
+                  (bp ? bp->status : 0),
+                  (bp ? bp->stream : 0),
+                  (bp ? bp->purb : 0),
+                  (bp ? bp->signature : 0));
+}
+
+static void pvr2_buffer_remove(struct pvr2_buffer *bp)
+{
+       unsigned int *cnt;
+       unsigned int *bcnt;
+       unsigned int ccnt;
+       struct pvr2_stream *sp = bp->stream;
+       switch (bp->state) {
+       case pvr2_buffer_state_idle:
+               cnt = &sp->i_count;
+               bcnt = &sp->i_bcount;
+               ccnt = bp->max_count;
+               break;
+       case pvr2_buffer_state_queued:
+               cnt = &sp->q_count;
+               bcnt = &sp->q_bcount;
+               ccnt = bp->max_count;
+               break;
+       case pvr2_buffer_state_ready:
+               cnt = &sp->r_count;
+               bcnt = &sp->r_bcount;
+               ccnt = bp->used_count;
+               break;
+       default:
+               return;
+       }
+       list_del_init(&bp->list_overhead);
+       (*cnt)--;
+       (*bcnt) -= ccnt;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/"
+                  " bufferPool     %8s dec cap=%07d cnt=%02d",
+                  pvr2_buffer_state_decode(bp->state),*bcnt,*cnt);
+       bp->state = pvr2_buffer_state_none;
+}
+
+static void pvr2_buffer_set_none(struct pvr2_buffer *bp)
+{
+       unsigned long irq_flags;
+       struct pvr2_stream *sp;
+       BUFFER_CHECK(bp);
+       sp = bp->stream;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",
+                  bp,
+                  pvr2_buffer_state_decode(bp->state),
+                  pvr2_buffer_state_decode(pvr2_buffer_state_none));
+       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       pvr2_buffer_remove(bp);
+       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
+static int pvr2_buffer_set_ready(struct pvr2_buffer *bp)
+{
+       int fl;
+       unsigned long irq_flags;
+       struct pvr2_stream *sp;
+       BUFFER_CHECK(bp);
+       sp = bp->stream;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",
+                  bp,
+                  pvr2_buffer_state_decode(bp->state),
+                  pvr2_buffer_state_decode(pvr2_buffer_state_ready));
+       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       fl = (sp->r_count == 0);
+       pvr2_buffer_remove(bp);
+       list_add_tail(&bp->list_overhead,&sp->ready_list);
+       bp->state = pvr2_buffer_state_ready;
+       (sp->r_count)++;
+       sp->r_bcount += bp->used_count;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/"
+                  " bufferPool     %8s inc cap=%07d cnt=%02d",
+                  pvr2_buffer_state_decode(bp->state),
+                  sp->r_bcount,sp->r_count);
+       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       return fl;
+}
+
+static void pvr2_buffer_set_idle(struct pvr2_buffer *bp)
+{
+       unsigned long irq_flags;
+       struct pvr2_stream *sp;
+       BUFFER_CHECK(bp);
+       sp = bp->stream;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",
+                  bp,
+                  pvr2_buffer_state_decode(bp->state),
+                  pvr2_buffer_state_decode(pvr2_buffer_state_idle));
+       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       pvr2_buffer_remove(bp);
+       list_add_tail(&bp->list_overhead,&sp->idle_list);
+       bp->state = pvr2_buffer_state_idle;
+       (sp->i_count)++;
+       sp->i_bcount += bp->max_count;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/"
+                  " bufferPool     %8s inc cap=%07d cnt=%02d",
+                  pvr2_buffer_state_decode(bp->state),
+                  sp->i_bcount,sp->i_count);
+       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
+static void pvr2_buffer_set_queued(struct pvr2_buffer *bp)
+{
+       unsigned long irq_flags;
+       struct pvr2_stream *sp;
+       BUFFER_CHECK(bp);
+       sp = bp->stream;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",
+                  bp,
+                  pvr2_buffer_state_decode(bp->state),
+                  pvr2_buffer_state_decode(pvr2_buffer_state_queued));
+       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       pvr2_buffer_remove(bp);
+       list_add_tail(&bp->list_overhead,&sp->queued_list);
+       bp->state = pvr2_buffer_state_queued;
+       (sp->q_count)++;
+       sp->q_bcount += bp->max_count;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/"
+                  " bufferPool     %8s inc cap=%07d cnt=%02d",
+                  pvr2_buffer_state_decode(bp->state),
+                  sp->q_bcount,sp->q_count);
+       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
+static void pvr2_buffer_wipe(struct pvr2_buffer *bp)
+{
+       if (bp->state == pvr2_buffer_state_queued) {
+               usb_kill_urb(bp->purb);
+       }
+}
+
+static int pvr2_buffer_init(struct pvr2_buffer *bp,
+                           struct pvr2_stream *sp,
+                           unsigned int id)
+{
+       memset(bp,0,sizeof(*bp));
+       bp->signature = BUFFER_SIG;
+       bp->id = id;
+       pvr2_trace(PVR2_TRACE_BUF_POOL,
+                  "/*---TRACE_FLOW---*/ bufferInit     %p stream=%p",bp,sp);
+       bp->stream = sp;
+       bp->state = pvr2_buffer_state_none;
+       INIT_LIST_HEAD(&bp->list_overhead);
+       bp->purb = usb_alloc_urb(0,GFP_KERNEL);
+       if (! bp->purb) return -ENOMEM;
+#ifdef SANITY_CHECK_BUFFERS
+       pvr2_buffer_describe(bp,"create");
+#endif
+       return 0;
+}
+
+static void pvr2_buffer_done(struct pvr2_buffer *bp)
+{
+#ifdef SANITY_CHECK_BUFFERS
+       pvr2_buffer_describe(bp,"delete");
+#endif
+       pvr2_buffer_wipe(bp);
+       pvr2_buffer_set_none(bp);
+       bp->signature = 0;
+       bp->stream = 0;
+       if (bp->purb) usb_free_urb(bp->purb);
+       pvr2_trace(PVR2_TRACE_BUF_POOL,"/*---TRACE_FLOW---*/"
+                  " bufferDone     %p",bp);
+}
+
+static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
+{
+       int ret;
+       unsigned int scnt;
+
+       /* Allocate buffers pointer array in multiples of 32 entries */
+       if (cnt == sp->buffer_total_count) return 0;
+
+       pvr2_trace(PVR2_TRACE_BUF_POOL,
+                  "/*---TRACE_FLOW---*/ poolResize    "
+                  " stream=%p cur=%d adj=%+d",
+                  sp,
+                  sp->buffer_total_count,
+                  cnt-sp->buffer_total_count);
+
+       scnt = cnt & ~0x1f;
+       if (cnt > scnt) scnt += 0x20;
+
+       if (cnt > sp->buffer_total_count) {
+               if (scnt > sp->buffer_slot_count) {
+                       struct pvr2_buffer **nb;
+                       nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL);
+                       if (!nb) return -ENOMEM;
+                       if (sp->buffer_slot_count) {
+                               memcpy(nb,sp->buffers,
+                                      sp->buffer_slot_count * sizeof(*nb));
+                               kfree(sp->buffers);
+                       }
+                       sp->buffers = nb;
+                       sp->buffer_slot_count = scnt;
+               }
+               while (sp->buffer_total_count < cnt) {
+                       struct pvr2_buffer *bp;
+                       bp = kmalloc(sizeof(*bp),GFP_KERNEL);
+                       if (!bp) return -ENOMEM;
+                       ret = pvr2_buffer_init(bp,sp,sp->buffer_total_count);
+                       if (ret) {
+                               kfree(bp);
+                               return -ENOMEM;
+                       }
+                       sp->buffers[sp->buffer_total_count] = bp;
+                       (sp->buffer_total_count)++;
+                       pvr2_buffer_set_idle(bp);
+               }
+       } else {
+               while (sp->buffer_total_count > cnt) {
+                       struct pvr2_buffer *bp;
+                       bp = sp->buffers[sp->buffer_total_count - 1];
+                       /* Paranoia */
+                       sp->buffers[sp->buffer_total_count - 1] = 0;
+                       (sp->buffer_total_count)--;
+                       pvr2_buffer_done(bp);
+                       kfree(bp);
+               }
+               if (scnt < sp->buffer_slot_count) {
+                       struct pvr2_buffer **nb = 0;
+                       if (scnt) {
+                               nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL);
+                               if (!nb) return -ENOMEM;
+                               memcpy(nb,sp->buffers,scnt * sizeof(*nb));
+                       }
+                       kfree(sp->buffers);
+                       sp->buffers = nb;
+                       sp->buffer_slot_count = scnt;
+               }
+       }
+       return 0;
+}
+
+static int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp)
+{
+       struct pvr2_buffer *bp;
+       unsigned int cnt;
+
+       if (sp->buffer_total_count == sp->buffer_target_count) return 0;
+
+       pvr2_trace(PVR2_TRACE_BUF_POOL,
+                  "/*---TRACE_FLOW---*/"
+                  " poolCheck      stream=%p cur=%d tgt=%d",
+                  sp,sp->buffer_total_count,sp->buffer_target_count);
+
+       if (sp->buffer_total_count < sp->buffer_target_count) {
+               return pvr2_stream_buffer_count(sp,sp->buffer_target_count);
+       }
+
+       cnt = 0;
+       while ((sp->buffer_total_count - cnt) > sp->buffer_target_count) {
+               bp = sp->buffers[sp->buffer_total_count - (cnt + 1)];
+               if (bp->state != pvr2_buffer_state_idle) break;
+               cnt++;
+       }
+       if (cnt) {
+               pvr2_stream_buffer_count(sp,sp->buffer_total_count - cnt);
+       }
+
+       return 0;
+}
+
+static void pvr2_stream_internal_flush(struct pvr2_stream *sp)
+{
+       struct list_head *lp;
+       struct pvr2_buffer *bp1;
+       while ((lp = sp->queued_list.next) != &sp->queued_list) {
+               bp1 = list_entry(lp,struct pvr2_buffer,list_overhead);
+               pvr2_buffer_wipe(bp1);
+               /* At this point, we should be guaranteed that no
+                  completion callback may happen on this buffer.  But it's
+                  possible that it might have completed after we noticed
+                  it but before we wiped it.  So double check its status
+                  here first. */
+               if (bp1->state != pvr2_buffer_state_queued) continue;
+               pvr2_buffer_set_idle(bp1);
+       }
+       if (sp->buffer_total_count != sp->buffer_target_count) {
+               pvr2_stream_achieve_buffer_count(sp);
+       }
+}
+
+static void pvr2_stream_init(struct pvr2_stream *sp)
+{
+       spin_lock_init(&sp->list_lock);
+       mutex_init(&sp->mutex);
+       INIT_LIST_HEAD(&sp->queued_list);
+       INIT_LIST_HEAD(&sp->ready_list);
+       INIT_LIST_HEAD(&sp->idle_list);
+}
+
+static void pvr2_stream_done(struct pvr2_stream *sp)
+{
+       mutex_lock(&sp->mutex); do {
+               pvr2_stream_internal_flush(sp);
+               pvr2_stream_buffer_count(sp,0);
+       } while (0); mutex_unlock(&sp->mutex);
+}
+
+static void buffer_complete(struct urb *urb, struct pt_regs *regs)
+{
+       struct pvr2_buffer *bp = urb->context;
+       struct pvr2_stream *sp;
+       unsigned long irq_flags;
+       BUFFER_CHECK(bp);
+       sp = bp->stream;
+       bp->used_count = 0;
+       bp->status = 0;
+       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                  "/*---TRACE_FLOW---*/ bufferComplete %p stat=%d cnt=%d",
+                  bp,urb->status,urb->actual_length);
+       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       if ((!(urb->status)) ||
+           (urb->status == -ENOENT) ||
+           (urb->status == -ECONNRESET) ||
+           (urb->status == -ESHUTDOWN)) {
+               bp->used_count = urb->actual_length;
+               if (sp->fail_count) {
+                       pvr2_trace(PVR2_TRACE_TOLERANCE,
+                                  "stream %p transfer ok"
+                                  " - fail count reset",sp);
+                       sp->fail_count = 0;
+               }
+       } else if (sp->fail_count < sp->fail_tolerance) {
+               // We can tolerate this error, because we're below the
+               // threshold...
+               (sp->fail_count)++;
+               pvr2_trace(PVR2_TRACE_TOLERANCE,
+                          "stream %p ignoring error %d"
+                          " - fail count increased to %u",
+                          sp,urb->status,sp->fail_count);
+       } else {
+               bp->status = urb->status;
+       }
+       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       pvr2_buffer_set_ready(bp);
+       if (sp && sp->callback_func) {
+               sp->callback_func(sp->callback_data);
+       }
+}
+
+struct pvr2_stream *pvr2_stream_create(void)
+{
+       struct pvr2_stream *sp;
+       sp = kmalloc(sizeof(*sp),GFP_KERNEL);
+       if (!sp) return sp;
+       memset(sp,0,sizeof(*sp));
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp);
+       pvr2_stream_init(sp);
+       return sp;
+}
+
+void pvr2_stream_destroy(struct pvr2_stream *sp)
+{
+       if (!sp) return;
+       pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_destroy: sp=%p",sp);
+       pvr2_stream_done(sp);
+       kfree(sp);
+}
+
+void pvr2_stream_setup(struct pvr2_stream *sp,
+                      struct usb_device *dev,
+                      int endpoint,
+                      unsigned int tolerance)
+{
+       mutex_lock(&sp->mutex); do {
+               pvr2_stream_internal_flush(sp);
+               sp->dev = dev;
+               sp->endpoint = endpoint;
+               sp->fail_tolerance = tolerance;
+       } while(0); mutex_unlock(&sp->mutex);
+}
+
+void pvr2_stream_set_callback(struct pvr2_stream *sp,
+                             pvr2_stream_callback func,
+                             void *data)
+{
+       unsigned long irq_flags;
+       mutex_lock(&sp->mutex); do {
+               spin_lock_irqsave(&sp->list_lock,irq_flags);
+               sp->callback_data = data;
+               sp->callback_func = func;
+               spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       } while(0); mutex_unlock(&sp->mutex);
+}
+
+/* Query / set the nominal buffer count */
+int pvr2_stream_get_buffer_count(struct pvr2_stream *sp)
+{
+       return sp->buffer_target_count;
+}
+
+int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
+{
+       int ret;
+       if (sp->buffer_target_count == cnt) return 0;
+       mutex_lock(&sp->mutex); do {
+               sp->buffer_target_count = cnt;
+               ret = pvr2_stream_achieve_buffer_count(sp);
+       } while(0); mutex_unlock(&sp->mutex);
+       return ret;
+}
+
+struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *sp)
+{
+       struct list_head *lp = sp->idle_list.next;
+       if (lp == &sp->idle_list) return 0;
+       return list_entry(lp,struct pvr2_buffer,list_overhead);
+}
+
+struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *sp)
+{
+       struct list_head *lp = sp->ready_list.next;
+       if (lp == &sp->ready_list) return 0;
+       return list_entry(lp,struct pvr2_buffer,list_overhead);
+}
+
+struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id)
+{
+       if (id < 0) return 0;
+       if (id >= sp->buffer_total_count) return 0;
+       return sp->buffers[id];
+}
+
+int pvr2_stream_get_ready_count(struct pvr2_stream *sp)
+{
+       return sp->r_count;
+}
+
+int pvr2_stream_get_idle_count(struct pvr2_stream *sp)
+{
+       return sp->i_count;
+}
+
+void pvr2_stream_flush(struct pvr2_stream *sp)
+{
+       mutex_lock(&sp->mutex); do {
+               pvr2_stream_internal_flush(sp);
+       } while(0); mutex_unlock(&sp->mutex);
+}
+
+void pvr2_stream_kill(struct pvr2_stream *sp)
+{
+       struct pvr2_buffer *bp;
+       mutex_lock(&sp->mutex); do {
+               pvr2_stream_internal_flush(sp);
+               while ((bp = pvr2_stream_get_ready_buffer(sp)) != 0) {
+                       pvr2_buffer_set_idle(bp);
+               }
+               if (sp->buffer_total_count != sp->buffer_target_count) {
+                       pvr2_stream_achieve_buffer_count(sp);
+               }
+       } while(0); mutex_unlock(&sp->mutex);
+}
+
+int pvr2_buffer_queue(struct pvr2_buffer *bp)
+{
+#undef SEED_BUFFER
+#ifdef SEED_BUFFER
+       unsigned int idx;
+       unsigned int val;
+#endif
+       int ret = 0;
+       struct pvr2_stream *sp;
+       if (!bp) return -EINVAL;
+       sp = bp->stream;
+       mutex_lock(&sp->mutex); do {
+               pvr2_buffer_wipe(bp);
+               if (!sp->dev) {
+                       ret = -EIO;
+                       break;
+               }
+               pvr2_buffer_set_queued(bp);
+#ifdef SEED_BUFFER
+               for (idx = 0; idx < (bp->max_count) / 4; idx++) {
+                       val = bp->id << 24;
+                       val |= idx;
+                       ((unsigned int *)(bp->ptr))[idx] = val;
+               }
+#endif
+               bp->status = -EINPROGRESS;
+               usb_fill_bulk_urb(bp->purb,      // struct urb *urb
+                                 sp->dev,       // struct usb_device *dev
+                                 // endpoint (below)
+                                 usb_rcvbulkpipe(sp->dev,sp->endpoint),
+                                 bp->ptr,       // void *transfer_buffer
+                                 bp->max_count, // int buffer_length
+                                 buffer_complete,
+                                 bp);
+               usb_submit_urb(bp->purb,GFP_KERNEL);
+       } while(0); mutex_unlock(&sp->mutex);
+       return ret;
+}
+
+int pvr2_buffer_idle(struct pvr2_buffer *bp)
+{
+       struct pvr2_stream *sp;
+       if (!bp) return -EINVAL;
+       sp = bp->stream;
+       mutex_lock(&sp->mutex); do {
+               pvr2_buffer_wipe(bp);
+               pvr2_buffer_set_idle(bp);
+               if (sp->buffer_total_count != sp->buffer_target_count) {
+                       pvr2_stream_achieve_buffer_count(sp);
+               }
+       } while(0); mutex_unlock(&sp->mutex);
+       return 0;
+}
+
+int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt)
+{
+       int ret = 0;
+       unsigned long irq_flags;
+       struct pvr2_stream *sp;
+       if (!bp) return -EINVAL;
+       sp = bp->stream;
+       mutex_lock(&sp->mutex); do {
+               spin_lock_irqsave(&sp->list_lock,irq_flags);
+               if (bp->state != pvr2_buffer_state_idle) {
+                       ret = -EPERM;
+               } else {
+                       bp->ptr = ptr;
+                       bp->stream->i_bcount -= bp->max_count;
+                       bp->max_count = cnt;
+                       bp->stream->i_bcount += bp->max_count;
+                       pvr2_trace(PVR2_TRACE_BUF_FLOW,
+                                  "/*---TRACE_FLOW---*/ bufferPool    "
+                                  " %8s cap cap=%07d cnt=%02d",
+                                  pvr2_buffer_state_decode(
+                                          pvr2_buffer_state_idle),
+                                  bp->stream->i_bcount,bp->stream->i_count);
+               }
+               spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       } while(0); mutex_unlock(&sp->mutex);
+       return ret;
+}
+
+unsigned int pvr2_buffer_get_count(struct pvr2_buffer *bp)
+{
+       return bp->used_count;
+}
+
+int pvr2_buffer_get_status(struct pvr2_buffer *bp)
+{
+       return bp->status;
+}
+
+enum pvr2_buffer_state pvr2_buffer_get_state(struct pvr2_buffer *bp)
+{
+       return bp->state;
+}
+
+int pvr2_buffer_get_id(struct pvr2_buffer *bp)
+{
+       return bp->id;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/video/pvrusb2/pvrusb2-io.h
new file mode 100644 (file)
index 0000000..65e1138
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_IO_H
+#define __PVRUSB2_IO_H
+
+#include <linux/usb.h>
+#include <linux/list.h>
+
+typedef void (*pvr2_stream_callback)(void *);
+
+enum pvr2_buffer_state {
+       pvr2_buffer_state_none = 0,   // Not on any list
+       pvr2_buffer_state_idle = 1,   // Buffer is ready to be used again
+       pvr2_buffer_state_queued = 2, // Buffer has been queued for filling
+       pvr2_buffer_state_ready = 3,  // Buffer has data available
+};
+
+struct pvr2_stream;
+struct pvr2_buffer;
+
+const char *pvr2_buffer_state_decode(enum pvr2_buffer_state);
+
+/* Initialize / tear down stream structure */
+struct pvr2_stream *pvr2_stream_create(void);
+void pvr2_stream_destroy(struct pvr2_stream *);
+void pvr2_stream_setup(struct pvr2_stream *,
+                      struct usb_device *dev,int endpoint,
+                      unsigned int tolerance);
+void pvr2_stream_set_callback(struct pvr2_stream *,
+                             pvr2_stream_callback func,
+                             void *data);
+
+/* Query / set the nominal buffer count */
+int pvr2_stream_get_buffer_count(struct pvr2_stream *);
+int pvr2_stream_set_buffer_count(struct pvr2_stream *,unsigned int);
+
+/* Get a pointer to a buffer that is either idle, ready, or is specified
+   named. */
+struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *);
+struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *);
+struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id);
+
+/* Find out how many buffers are idle or ready */
+int pvr2_stream_get_idle_count(struct pvr2_stream *);
+int pvr2_stream_get_ready_count(struct pvr2_stream *);
+
+/* Kill all pending operations */
+void pvr2_stream_flush(struct pvr2_stream *);
+
+/* Kill all pending buffers and throw away any ready buffers as well */
+void pvr2_stream_kill(struct pvr2_stream *);
+
+/* Set up the actual storage for a buffer */
+int pvr2_buffer_set_buffer(struct pvr2_buffer *,void *ptr,unsigned int cnt);
+
+/* Find out size of data in the given ready buffer */
+unsigned int pvr2_buffer_get_count(struct pvr2_buffer *);
+
+/* Retrieve completion code for given ready buffer */
+int pvr2_buffer_get_status(struct pvr2_buffer *);
+
+/* Retrieve state of given buffer */
+enum pvr2_buffer_state pvr2_buffer_get_state(struct pvr2_buffer *);
+
+/* Retrieve ID of given buffer */
+int pvr2_buffer_get_id(struct pvr2_buffer *);
+
+/* Start reading into given buffer (kill it if needed) */
+int pvr2_buffer_queue(struct pvr2_buffer *);
+
+/* Move buffer back to idle pool (kill it if needed) */
+int pvr2_buffer_idle(struct pvr2_buffer *);
+
+#endif /* __PVRUSB2_IO_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
new file mode 100644 (file)
index 0000000..49da062
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 "pvrusb2-ioread.h"
+#include "pvrusb2-debug.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+
+#define BUFFER_COUNT 32
+#define BUFFER_SIZE PAGE_ALIGN(0x4000)
+
+struct pvr2_ioread {
+       struct pvr2_stream *stream;
+       char *buffer_storage[BUFFER_COUNT];
+       char *sync_key_ptr;
+       unsigned int sync_key_len;
+       unsigned int sync_buf_offs;
+       unsigned int sync_state;
+       unsigned int sync_trashed_count;
+       int enabled;         // Streaming is on
+       int spigot_open;     // OK to pass data to client
+       int stream_running;  // Passing data to client now
+
+       /* State relevant to current buffer being read */
+       struct pvr2_buffer *c_buf;
+       char *c_data_ptr;
+       unsigned int c_data_len;
+       unsigned int c_data_offs;
+       struct mutex mutex;
+};
+
+static int pvr2_ioread_init(struct pvr2_ioread *cp)
+{
+       unsigned int idx;
+
+       cp->stream = 0;
+       mutex_init(&cp->mutex);
+
+       for (idx = 0; idx < BUFFER_COUNT; idx++) {
+               cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL);
+               if (!(cp->buffer_storage[idx])) break;
+       }
+
+       if (idx < BUFFER_COUNT) {
+               // An allocation appears to have failed
+               for (idx = 0; idx < BUFFER_COUNT; idx++) {
+                       if (!(cp->buffer_storage[idx])) continue;
+                       kfree(cp->buffer_storage[idx]);
+               }
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void pvr2_ioread_done(struct pvr2_ioread *cp)
+{
+       unsigned int idx;
+
+       pvr2_ioread_setup(cp,0);
+       for (idx = 0; idx < BUFFER_COUNT; idx++) {
+               if (!(cp->buffer_storage[idx])) continue;
+               kfree(cp->buffer_storage[idx]);
+       }
+}
+
+struct pvr2_ioread *pvr2_ioread_create(void)
+{
+       struct pvr2_ioread *cp;
+       cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+       if (!cp) return 0;
+       pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
+       memset(cp,0,sizeof(*cp));
+       if (pvr2_ioread_init(cp) < 0) {
+               kfree(cp);
+               return 0;
+       }
+       return cp;
+}
+
+void pvr2_ioread_destroy(struct pvr2_ioread *cp)
+{
+       if (!cp) return;
+       pvr2_ioread_done(cp);
+       pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp);
+       if (cp->sync_key_ptr) {
+               kfree(cp->sync_key_ptr);
+               cp->sync_key_ptr = 0;
+       }
+       kfree(cp);
+}
+
+void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp,
+                             const char *sync_key_ptr,
+                             unsigned int sync_key_len)
+{
+       if (!cp) return;
+
+       if (!sync_key_ptr) sync_key_len = 0;
+       if ((sync_key_len == cp->sync_key_len) &&
+           ((!sync_key_len) ||
+            (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return;
+
+       if (sync_key_len != cp->sync_key_len) {
+               if (cp->sync_key_ptr) {
+                       kfree(cp->sync_key_ptr);
+                       cp->sync_key_ptr = 0;
+               }
+               cp->sync_key_len = 0;
+               if (sync_key_len) {
+                       cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL);
+                       if (cp->sync_key_ptr) {
+                               cp->sync_key_len = sync_key_len;
+                       }
+               }
+       }
+       if (!cp->sync_key_len) return;
+       memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len);
+}
+
+static void pvr2_ioread_stop(struct pvr2_ioread *cp)
+{
+       if (!(cp->enabled)) return;
+       pvr2_trace(PVR2_TRACE_START_STOP,
+                  "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp);
+       pvr2_stream_kill(cp->stream);
+       cp->c_buf = 0;
+       cp->c_data_ptr = 0;
+       cp->c_data_len = 0;
+       cp->c_data_offs = 0;
+       cp->enabled = 0;
+       cp->stream_running = 0;
+       cp->spigot_open = 0;
+       if (cp->sync_state) {
+               pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                          "/*---TRACE_READ---*/ sync_state <== 0");
+               cp->sync_state = 0;
+       }
+}
+
+static int pvr2_ioread_start(struct pvr2_ioread *cp)
+{
+       int stat;
+       struct pvr2_buffer *bp;
+       if (cp->enabled) return 0;
+       if (!(cp->stream)) return 0;
+       pvr2_trace(PVR2_TRACE_START_STOP,
+                  "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
+       while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != 0) {
+               stat = pvr2_buffer_queue(bp);
+               if (stat < 0) {
+                       pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                                  "/*---TRACE_READ---*/"
+                                  " pvr2_ioread_start id=%p"
+                                  " error=%d",
+                                  cp,stat);
+                       pvr2_ioread_stop(cp);
+                       return stat;
+               }
+       }
+       cp->enabled = !0;
+       cp->c_buf = 0;
+       cp->c_data_ptr = 0;
+       cp->c_data_len = 0;
+       cp->c_data_offs = 0;
+       cp->stream_running = 0;
+       if (cp->sync_key_len) {
+               pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                          "/*---TRACE_READ---*/ sync_state <== 1");
+               cp->sync_state = 1;
+               cp->sync_trashed_count = 0;
+               cp->sync_buf_offs = 0;
+       }
+       cp->spigot_open = 0;
+       return 0;
+}
+
+struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp)
+{
+       return cp->stream;
+}
+
+int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
+{
+       int ret;
+       unsigned int idx;
+       struct pvr2_buffer *bp;
+
+       mutex_lock(&cp->mutex); do {
+               if (cp->stream) {
+                       pvr2_trace(PVR2_TRACE_START_STOP,
+                                  "/*---TRACE_READ---*/"
+                                  " pvr2_ioread_setup (tear-down) id=%p",cp);
+                       pvr2_ioread_stop(cp);
+                       pvr2_stream_kill(cp->stream);
+                       pvr2_stream_set_buffer_count(cp->stream,0);
+                       cp->stream = 0;
+               }
+               if (sp) {
+                       pvr2_trace(PVR2_TRACE_START_STOP,
+                                  "/*---TRACE_READ---*/"
+                                  " pvr2_ioread_setup (setup) id=%p",cp);
+                       pvr2_stream_kill(sp);
+                       ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
+                       if (ret < 0) return ret;
+                       for (idx = 0; idx < BUFFER_COUNT; idx++) {
+                               bp = pvr2_stream_get_buffer(sp,idx);
+                               pvr2_buffer_set_buffer(bp,
+                                                      cp->buffer_storage[idx],
+                                                      BUFFER_SIZE);
+                       }
+                       cp->stream = sp;
+               }
+       } while (0); mutex_unlock(&cp->mutex);
+
+       return 0;
+}
+
+int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl)
+{
+       int ret = 0;
+       if ((!fl) == (!(cp->enabled))) return ret;
+
+       mutex_lock(&cp->mutex); do {
+               if (fl) {
+                       ret = pvr2_ioread_start(cp);
+               } else {
+                       pvr2_ioread_stop(cp);
+               }
+       } while (0); mutex_unlock(&cp->mutex);
+       return ret;
+}
+
+int pvr2_ioread_get_enabled(struct pvr2_ioread *cp)
+{
+       return cp->enabled != 0;
+}
+
+int pvr2_ioread_get_buffer(struct pvr2_ioread *cp)
+{
+       int stat;
+
+       while (cp->c_data_len <= cp->c_data_offs) {
+               if (cp->c_buf) {
+                       // Flush out current buffer first.
+                       stat = pvr2_buffer_queue(cp->c_buf);
+                       if (stat < 0) {
+                               // Streaming error...
+                               pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                                          "/*---TRACE_READ---*/"
+                                          " pvr2_ioread_read id=%p"
+                                          " queue_error=%d",
+                                          cp,stat);
+                               pvr2_ioread_stop(cp);
+                               return 0;
+                       }
+                       cp->c_buf = 0;
+                       cp->c_data_ptr = 0;
+                       cp->c_data_len = 0;
+                       cp->c_data_offs = 0;
+               }
+               // Now get a freshly filled buffer.
+               cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream);
+               if (!cp->c_buf) break; // Nothing ready; done.
+               cp->c_data_len = pvr2_buffer_get_count(cp->c_buf);
+               if (!cp->c_data_len) {
+                       // Nothing transferred.  Was there an error?
+                       stat = pvr2_buffer_get_status(cp->c_buf);
+                       if (stat < 0) {
+                               // Streaming error...
+                               pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                                          "/*---TRACE_READ---*/"
+                                          " pvr2_ioread_read id=%p"
+                                          " buffer_error=%d",
+                                          cp,stat);
+                               pvr2_ioread_stop(cp);
+                               // Give up.
+                               return 0;
+                       }
+                       // Start over...
+                       continue;
+               }
+               cp->c_data_offs = 0;
+               cp->c_data_ptr = cp->buffer_storage[
+                       pvr2_buffer_get_id(cp->c_buf)];
+       }
+       return !0;
+}
+
+void pvr2_ioread_filter(struct pvr2_ioread *cp)
+{
+       unsigned int idx;
+       if (!cp->enabled) return;
+       if (cp->sync_state != 1) return;
+
+       // Search the stream for our synchronization key.  This is made
+       // complicated by the fact that in order to be honest with
+       // ourselves here we must search across buffer boundaries...
+       mutex_lock(&cp->mutex); while (1) {
+               // Ensure we have a buffer
+               if (!pvr2_ioread_get_buffer(cp)) break;
+               if (!cp->c_data_len) break;
+
+               // Now walk the buffer contents until we match the key or
+               // run out of buffer data.
+               for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) {
+                       if (cp->sync_buf_offs >= cp->sync_key_len) break;
+                       if (cp->c_data_ptr[idx] ==
+                           cp->sync_key_ptr[cp->sync_buf_offs]) {
+                               // Found the next key byte
+                               (cp->sync_buf_offs)++;
+                       } else {
+                               // Whoops, mismatched.  Start key over...
+                               cp->sync_buf_offs = 0;
+                       }
+               }
+
+               // Consume what we've walked through
+               cp->c_data_offs += idx;
+               cp->sync_trashed_count += idx;
+
+               // If we've found the key, then update state and get out.
+               if (cp->sync_buf_offs >= cp->sync_key_len) {
+                       cp->sync_trashed_count -= cp->sync_key_len;
+                       pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                                  "/*---TRACE_READ---*/"
+                                  " sync_state <== 2 (skipped %u bytes)",
+                                  cp->sync_trashed_count);
+                       cp->sync_state = 2;
+                       cp->sync_buf_offs = 0;
+                       break;
+               }
+
+               if (cp->c_data_offs < cp->c_data_len) {
+                       // Sanity check - should NEVER get here
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "ERROR: pvr2_ioread filter sync problem"
+                                  " len=%u offs=%u",
+                                  cp->c_data_len,cp->c_data_offs);
+                       // Get out so we don't get stuck in an infinite
+                       // loop.
+                       break;
+               }
+
+               continue; // (for clarity)
+       } mutex_unlock(&cp->mutex);
+}
+
+int pvr2_ioread_avail(struct pvr2_ioread *cp)
+{
+       int ret;
+       if (!(cp->enabled)) {
+               // Stream is not enabled; so this is an I/O error
+               return -EIO;
+       }
+
+       if (cp->sync_state == 1) {
+               pvr2_ioread_filter(cp);
+               if (cp->sync_state == 1) return -EAGAIN;
+       }
+
+       ret = 0;
+       if (cp->stream_running) {
+               if (!pvr2_stream_get_ready_count(cp->stream)) {
+                       // No data available at all right now.
+                       ret = -EAGAIN;
+               }
+       } else {
+               if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) {
+                       // Haven't buffered up enough yet; try again later
+                       ret = -EAGAIN;
+               }
+       }
+
+       if ((!(cp->spigot_open)) != (!(ret == 0))) {
+               cp->spigot_open = (ret == 0);
+               pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                          "/*---TRACE_READ---*/ data is %s",
+                          cp->spigot_open ? "available" : "pending");
+       }
+
+       return ret;
+}
+
+int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt)
+{
+       unsigned int copied_cnt;
+       unsigned int bcnt;
+       const char *src;
+       int stat;
+       int ret = 0;
+       unsigned int req_cnt = cnt;
+
+       if (!cnt) {
+               pvr2_trace(PVR2_TRACE_TRAP,
+                          "/*---TRACE_READ---*/ pvr2_ioread_read id=%p"
+                          " ZERO Request? Returning zero.",cp);
+               return 0;
+       }
+
+       stat = pvr2_ioread_avail(cp);
+       if (stat < 0) return stat;
+
+       cp->stream_running = !0;
+
+       mutex_lock(&cp->mutex); do {
+
+               // Suck data out of the buffers and copy to the user
+               copied_cnt = 0;
+               if (!buf) cnt = 0;
+               while (1) {
+                       if (!pvr2_ioread_get_buffer(cp)) {
+                               ret = -EIO;
+                               break;
+                       }
+
+                       if (!cnt) break;
+
+                       if (cp->sync_state == 2) {
+                               // We're repeating the sync key data into
+                               // the stream.
+                               src = cp->sync_key_ptr + cp->sync_buf_offs;
+                               bcnt = cp->sync_key_len - cp->sync_buf_offs;
+                       } else {
+                               // Normal buffer copy
+                               src = cp->c_data_ptr + cp->c_data_offs;
+                               bcnt = cp->c_data_len - cp->c_data_offs;
+                       }
+
+                       if (!bcnt) break;
+
+                       // Don't run past user's buffer
+                       if (bcnt > cnt) bcnt = cnt;
+
+                       if (copy_to_user(buf,src,bcnt)) {
+                               // User supplied a bad pointer?
+                               // Give up - this *will* cause data
+                               // to be lost.
+                               ret = -EFAULT;
+                               break;
+                       }
+                       cnt -= bcnt;
+                       buf += bcnt;
+                       copied_cnt += bcnt;
+
+                       if (cp->sync_state == 2) {
+                               // Update offset inside sync key that we're
+                               // repeating back out.
+                               cp->sync_buf_offs += bcnt;
+                               if (cp->sync_buf_offs >= cp->sync_key_len) {
+                                       // Consumed entire key; switch mode
+                                       // to normal.
+                                       pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                                                  "/*---TRACE_READ---*/"
+                                                  " sync_state <== 0");
+                                       cp->sync_state = 0;
+                               }
+                       } else {
+                               // Update buffer offset.
+                               cp->c_data_offs += bcnt;
+                       }
+               }
+
+       } while (0); mutex_unlock(&cp->mutex);
+
+       if (!ret) {
+               if (copied_cnt) {
+                       // If anything was copied, return that count
+                       ret = copied_cnt;
+               } else {
+                       // Nothing copied; suggest to caller that another
+                       // attempt should be tried again later
+                       ret = -EAGAIN;
+               }
+       }
+
+       pvr2_trace(PVR2_TRACE_DATA_FLOW,
+                  "/*---TRACE_READ---*/ pvr2_ioread_read"
+                  " id=%p request=%d result=%d",
+                  cp,req_cnt,ret);
+       return ret;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.h b/drivers/media/video/pvrusb2/pvrusb2-ioread.h
new file mode 100644 (file)
index 0000000..6b00259
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_IOREAD_H
+#define __PVRUSB2_IOREAD_H
+
+#include "pvrusb2-io.h"
+
+struct pvr2_ioread;
+
+struct pvr2_ioread *pvr2_ioread_create(void);
+void pvr2_ioread_destroy(struct pvr2_ioread *);
+int pvr2_ioread_setup(struct pvr2_ioread *,struct pvr2_stream *);
+struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *);
+void pvr2_ioread_set_sync_key(struct pvr2_ioread *,
+                             const char *sync_key_ptr,
+                             unsigned int sync_key_len);
+int pvr2_ioread_set_enabled(struct pvr2_ioread *,int fl);
+int pvr2_ioread_get_enabled(struct pvr2_ioread *);
+int pvr2_ioread_read(struct pvr2_ioread *,void __user *buf,unsigned int cnt);
+int pvr2_ioread_avail(struct pvr2_ioread *);
+
+#endif /* __PVRUSB2_IOREAD_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
new file mode 100644 (file)
index 0000000..b952482
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-context.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-v4l2.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+#include "pvrusb2-sysfs.h"
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+#define DRIVER_AUTHOR "Mike Isely <isely@pobox.com>"
+#define DRIVER_DESC "Hauppauge WinTV-PVR-USB2 MPEG2 Encoder/Tuner"
+#define DRIVER_VERSION "V4L in-tree version"
+
+#define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \
+                           PVR2_TRACE_INFO| \
+                           PVR2_TRACE_TOLERANCE| \
+                           PVR2_TRACE_TRAP| \
+                           0)
+
+int pvrusb2_debug = DEFAULT_DEBUG_MASK;
+
+module_param_named(debug,pvrusb2_debug,int,S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug trace mask");
+
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+static struct pvr2_sysfs_class *class_ptr = 0;
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+static void pvr_setup_attach(struct pvr2_context *pvr)
+{
+       /* Create association with v4l layer */
+       pvr2_v4l2_create(pvr);
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+       pvr2_sysfs_create(pvr,class_ptr);
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+}
+
+static int pvr_probe(struct usb_interface *intf,
+                    const struct usb_device_id *devid)
+{
+       struct pvr2_context *pvr;
+
+       /* Create underlying hardware interface */
+       pvr = pvr2_context_create(intf,devid,pvr_setup_attach);
+       if (!pvr) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Failed to create hdw handler");
+               return -ENOMEM;
+       }
+
+       pvr2_trace(PVR2_TRACE_INIT,"pvr_probe(pvr=%p)",pvr);
+
+       usb_set_intfdata(intf, pvr);
+
+       return 0;
+}
+
+/*
+ * pvr_disconnect()
+ *
+ */
+static void pvr_disconnect(struct usb_interface *intf)
+{
+       struct pvr2_context *pvr = usb_get_intfdata(intf);
+
+       pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) BEGIN",pvr);
+
+       usb_set_intfdata (intf, NULL);
+       pvr2_context_disconnect(pvr);
+
+       pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) DONE",pvr);
+
+}
+
+static struct usb_driver pvr_driver = {
+       name:           "pvrusb2",
+       id_table:       pvr2_device_table,
+       probe:          pvr_probe,
+       disconnect:     pvr_disconnect
+};
+
+/*
+ * pvr_init() / pvr_exit()
+ *
+ * This code is run to initialize/exit the driver.
+ *
+ */
+static int __init pvr_init(void)
+{
+       int ret;
+
+       pvr2_trace(PVR2_TRACE_INIT,"pvr_init");
+
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+       class_ptr = pvr2_sysfs_class_create();
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+       ret = usb_register(&pvr_driver);
+
+       if (ret == 0)
+               info(DRIVER_DESC " : " DRIVER_VERSION);
+       if (pvrusb2_debug) info("Debug mask is %d (0x%x)",
+                               pvrusb2_debug,pvrusb2_debug);
+
+       return ret;
+}
+
+static void __exit pvr_exit(void)
+{
+
+       pvr2_trace(PVR2_TRACE_INIT,"pvr_exit");
+
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+       pvr2_sysfs_class_destroy(class_ptr);
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+       usb_deregister(&pvr_driver);
+}
+
+module_init(pvr_init);
+module_exit(pvr_exit);
+
+/* Mike Isely <mcisely@pobox.com> 11-Mar-2006: See pvrusb2-hdw.c for
+   MODULE_DEVICE_TABLE().  We have to declare that attribute there
+   because that's where the device table actually is now and it seems
+   that certain gcc configurations get angry if MODULE_DEVICE_TABLE()
+   is used on what ends up being an external symbol. */
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
new file mode 100644 (file)
index 0000000..1340636
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 "pvrusb2-std.h"
+#include "pvrusb2-debug.h"
+#include <asm/string.h>
+#include <linux/slab.h>
+
+struct std_name {
+       const char *name;
+       v4l2_std_id id;
+};
+
+
+#define CSTD_PAL \
+       (V4L2_STD_PAL_B| \
+        V4L2_STD_PAL_B1| \
+        V4L2_STD_PAL_G| \
+        V4L2_STD_PAL_H| \
+        V4L2_STD_PAL_I| \
+        V4L2_STD_PAL_D| \
+        V4L2_STD_PAL_D1| \
+        V4L2_STD_PAL_K| \
+        V4L2_STD_PAL_M| \
+        V4L2_STD_PAL_N| \
+        V4L2_STD_PAL_Nc| \
+        V4L2_STD_PAL_60)
+
+#define CSTD_NTSC \
+       (V4L2_STD_NTSC_M| \
+        V4L2_STD_NTSC_M_JP| \
+        V4L2_STD_NTSC_M_KR| \
+        V4L2_STD_NTSC_443)
+
+#define CSTD_SECAM \
+       (V4L2_STD_SECAM_B| \
+        V4L2_STD_SECAM_D| \
+        V4L2_STD_SECAM_G| \
+        V4L2_STD_SECAM_H| \
+        V4L2_STD_SECAM_K| \
+        V4L2_STD_SECAM_K1| \
+        V4L2_STD_SECAM_L| \
+        V4L2_STD_SECAM_LC)
+
+#define TSTD_B   (V4L2_STD_PAL_B|V4L2_STD_SECAM_B)
+#define TSTD_B1  (V4L2_STD_PAL_B1)
+#define TSTD_D   (V4L2_STD_PAL_D|V4L2_STD_SECAM_D)
+#define TSTD_D1  (V4L2_STD_PAL_D1)
+#define TSTD_G   (V4L2_STD_PAL_G|V4L2_STD_SECAM_G)
+#define TSTD_H   (V4L2_STD_PAL_H|V4L2_STD_SECAM_H)
+#define TSTD_I   (V4L2_STD_PAL_I)
+#define TSTD_K   (V4L2_STD_PAL_K|V4L2_STD_SECAM_K)
+#define TSTD_K1  (V4L2_STD_SECAM_K1)
+#define TSTD_L   (V4L2_STD_SECAM_L)
+#define TSTD_M   (V4L2_STD_PAL_M|V4L2_STD_NTSC_M)
+#define TSTD_N   (V4L2_STD_PAL_N)
+#define TSTD_Nc  (V4L2_STD_PAL_Nc)
+#define TSTD_60  (V4L2_STD_PAL_60)
+
+#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_SECAM)
+
+/* Mapping of standard bits to color system */
+const static struct std_name std_groups[] = {
+       {"PAL",CSTD_PAL},
+       {"NTSC",CSTD_NTSC},
+       {"SECAM",CSTD_SECAM},
+};
+
+/* Mapping of standard bits to modulation system */
+const static struct std_name std_items[] = {
+       {"B",TSTD_B},
+       {"B1",TSTD_B1},
+       {"D",TSTD_D},
+       {"D1",TSTD_D1},
+       {"G",TSTD_G},
+       {"H",TSTD_H},
+       {"I",TSTD_I},
+       {"K",TSTD_K},
+       {"K1",TSTD_K1},
+       {"L",TSTD_L},
+       {"LC",V4L2_STD_SECAM_LC},
+       {"M",TSTD_M},
+       {"Mj",V4L2_STD_NTSC_M_JP},
+       {"443",V4L2_STD_NTSC_443},
+       {"Mk",V4L2_STD_NTSC_M_KR},
+       {"N",TSTD_N},
+       {"Nc",TSTD_Nc},
+       {"60",TSTD_60},
+};
+
+
+// Search an array of std_name structures and return a pointer to the
+// element with the matching name.
+static const struct std_name *find_std_name(const struct std_name *arrPtr,
+                                           unsigned int arrSize,
+                                           const char *bufPtr,
+                                           unsigned int bufSize)
+{
+       unsigned int idx;
+       const struct std_name *p;
+       for (idx = 0; idx < arrSize; idx++) {
+               p = arrPtr + idx;
+               if (strlen(p->name) != bufSize) continue;
+               if (!memcmp(bufPtr,p->name,bufSize)) return p;
+       }
+       return 0;
+}
+
+
+int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
+                      unsigned int bufSize)
+{
+       v4l2_std_id id = 0;
+       v4l2_std_id cmsk = 0;
+       v4l2_std_id t;
+       int mMode = 0;
+       unsigned int cnt;
+       char ch;
+       const struct std_name *sp;
+
+       while (bufSize) {
+               if (!mMode) {
+                       cnt = 0;
+                       while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
+                       if (cnt >= bufSize) return 0; // No more characters
+                       sp = find_std_name(
+                               std_groups,
+                               sizeof(std_groups)/sizeof(std_groups[0]),
+                               bufPtr,cnt);
+                       if (!sp) return 0; // Illegal color system name
+                       cnt++;
+                       bufPtr += cnt;
+                       bufSize -= cnt;
+                       mMode = !0;
+                       cmsk = sp->id;
+                       continue;
+               }
+               cnt = 0;
+               while (cnt < bufSize) {
+                       ch = bufPtr[cnt];
+                       if (ch == ';') {
+                               mMode = 0;
+                               break;
+                       }
+                       if (ch == '/') break;
+                       cnt++;
+               }
+               sp = find_std_name(std_items,
+                                  sizeof(std_items)/sizeof(std_items[0]),
+                                  bufPtr,cnt);
+               if (!sp) return 0; // Illegal modulation system ID
+               t = sp->id & cmsk;
+               if (!t) return 0; // Specific color + modulation system illegal
+               id |= t;
+               if (cnt < bufSize) cnt++;
+               bufPtr += cnt;
+               bufSize -= cnt;
+       }
+
+       if (idPtr) *idPtr = id;
+       return !0;
+}
+
+
+unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
+                               v4l2_std_id id)
+{
+       unsigned int idx1,idx2;
+       const struct std_name *ip,*gp;
+       int gfl,cfl;
+       unsigned int c1,c2;
+       cfl = 0;
+       c1 = 0;
+       for (idx1 = 0;
+            idx1 < sizeof(std_groups)/sizeof(std_groups[0]);
+            idx1++) {
+               gp = std_groups + idx1;
+               gfl = 0;
+               for (idx2 = 0;
+                    idx2 < sizeof(std_items)/sizeof(std_items[0]);
+                    idx2++) {
+                       ip = std_items + idx2;
+                       if (!(gp->id & ip->id & id)) continue;
+                       if (!gfl) {
+                               if (cfl) {
+                                       c2 = scnprintf(bufPtr,bufSize,";");
+                                       c1 += c2;
+                                       bufSize -= c2;
+                                       bufPtr += c2;
+                               }
+                               cfl = !0;
+                               c2 = scnprintf(bufPtr,bufSize,
+                                              "%s-",gp->name);
+                               gfl = !0;
+                       } else {
+                               c2 = scnprintf(bufPtr,bufSize,"/");
+                       }
+                       c1 += c2;
+                       bufSize -= c2;
+                       bufPtr += c2;
+                       c2 = scnprintf(bufPtr,bufSize,
+                                      ip->name);
+                       c1 += c2;
+                       bufSize -= c2;
+                       bufPtr += c2;
+               }
+       }
+       return c1;
+}
+
+
+// Template data for possible enumerated video standards.  Here we group
+// standards which share common frame rates and resolution.
+static struct v4l2_standard generic_standards[] = {
+       {
+               .id             = (TSTD_B|TSTD_B1|
+                                  TSTD_D|TSTD_D1|
+                                  TSTD_G|
+                                  TSTD_H|
+                                  TSTD_I|
+                                  TSTD_K|TSTD_K1|
+                                  TSTD_L|
+                                  V4L2_STD_SECAM_LC |
+                                  TSTD_N|TSTD_Nc),
+               .frameperiod    =
+               {
+                       .numerator  = 1,
+                       .denominator= 25
+               },
+               .framelines     = 625,
+               .reserved       = {0,0,0,0}
+       }, {
+               .id             = (TSTD_M|
+                                  V4L2_STD_NTSC_M_JP|
+                                  V4L2_STD_NTSC_M_KR),
+               .frameperiod    =
+               {
+                       .numerator  = 1001,
+                       .denominator= 30000
+               },
+               .framelines     = 525,
+               .reserved       = {0,0,0,0}
+       }, { // This is a total wild guess
+               .id             = (TSTD_60),
+               .frameperiod    =
+               {
+                       .numerator  = 1001,
+                       .denominator= 30000
+               },
+               .framelines     = 525,
+               .reserved       = {0,0,0,0}
+       }, { // This is total wild guess
+               .id             = V4L2_STD_NTSC_443,
+               .frameperiod    =
+               {
+                       .numerator  = 1001,
+                       .denominator= 30000
+               },
+               .framelines     = 525,
+               .reserved       = {0,0,0,0}
+       }
+};
+
+#define generic_standards_cnt (sizeof(generic_standards)/sizeof(generic_standards[0]))
+
+static struct v4l2_standard *match_std(v4l2_std_id id)
+{
+       unsigned int idx;
+       for (idx = 0; idx < generic_standards_cnt; idx++) {
+               if (generic_standards[idx].id & id) {
+                       return generic_standards + idx;
+               }
+       }
+       return 0;
+}
+
+static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id)
+{
+       struct v4l2_standard *template;
+       int idx;
+       unsigned int bcnt;
+       template = match_std(id);
+       if (!template) return 0;
+       idx = std->index;
+       memcpy(std,template,sizeof(*template));
+       std->index = idx;
+       std->id = id;
+       bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id);
+       std->name[bcnt] = 0;
+       pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s",
+                  std->index,std->name);
+       return !0;
+}
+
+/* These are special cases of combined standards that we should enumerate
+   separately if the component pieces are present. */
+static v4l2_std_id std_mixes[] = {
+       V4L2_STD_PAL_B | V4L2_STD_PAL_G,
+       V4L2_STD_PAL_D | V4L2_STD_PAL_K,
+       V4L2_STD_SECAM_B | V4L2_STD_SECAM_G,
+       V4L2_STD_SECAM_D | V4L2_STD_SECAM_K,
+};
+
+struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
+                                          v4l2_std_id id)
+{
+       unsigned int std_cnt = 0;
+       unsigned int idx,bcnt,idx2;
+       v4l2_std_id idmsk,cmsk,fmsk;
+       struct v4l2_standard *stddefs;
+
+       if (pvrusb2_debug & PVR2_TRACE_INIT) {
+               char buf[50];
+               bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
+               pvr2_trace(
+                       PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)",
+                       (int)id,bcnt,buf);
+       }
+
+       *countptr = 0;
+       std_cnt = 0;
+       fmsk = 0;
+       for (idmsk = 1, cmsk = id; cmsk; idmsk <<= 1) {
+               if (!(idmsk & cmsk)) continue;
+               cmsk &= ~idmsk;
+               if (match_std(idmsk)) {
+                       std_cnt++;
+                       continue;
+               }
+               fmsk |= idmsk;
+       }
+
+       for (idx2 = 0; idx2 < sizeof(std_mixes)/sizeof(std_mixes[0]); idx2++) {
+               if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
+       }
+
+       if (fmsk) {
+               char buf[50];
+               bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "WARNING:"
+                       " Failed to classify the following standard(s): %.*s",
+                       bcnt,buf);
+       }
+
+       pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)",
+                  std_cnt);
+       if (!std_cnt) return 0; // paranoia
+
+       stddefs = kmalloc(sizeof(struct v4l2_standard) * std_cnt,
+                         GFP_KERNEL);
+       memset(stddefs,0,sizeof(struct v4l2_standard) * std_cnt);
+       for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
+
+       idx = 0;
+
+       /* Enumerate potential special cases */
+       for (idx2 = 0; ((idx2 < sizeof(std_mixes)/sizeof(std_mixes[0])) &&
+                       (idx < std_cnt)); idx2++) {
+               if (!(id & std_mixes[idx2])) continue;
+               if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
+       }
+       /* Now enumerate individual pieces */
+       for (idmsk = 1, cmsk = id; cmsk && (idx < std_cnt); idmsk <<= 1) {
+               if (!(idmsk & cmsk)) continue;
+               cmsk &= ~idmsk;
+               if (!pvr2_std_fill(stddefs+idx,idmsk)) continue;
+               idx++;
+       }
+
+       *countptr = std_cnt;
+       return stddefs;
+}
+
+v4l2_std_id pvr2_std_get_usable(void)
+{
+       return CSTD_ALL;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.h b/drivers/media/video/pvrusb2/pvrusb2-std.h
new file mode 100644 (file)
index 0000000..07c3993
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_STD_H
+#define __PVRUSB2_STD_H
+
+#include <linux/videodev2.h>
+
+// Convert string describing one or more video standards into a mask of V4L
+// standard bits.  Return true if conversion succeeds otherwise return
+// false.  String is expected to be of the form: C1-x/y;C2-a/b where C1 and
+// C2 are color system names (e.g. "PAL", "NTSC") and x, y, a, and b are
+// modulation schemes (e.g. "M", "B", "G", etc).
+int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
+                      unsigned int bufSize);
+
+// Convert any arbitrary set of video standard bits into an unambiguous
+// readable string.  Return value is the number of bytes consumed in the
+// buffer.  The formatted string is of a form that can be parsed by our
+// sibling std_std_to_id() function.
+unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
+                               v4l2_std_id id);
+
+// Create an array of suitable v4l2_standard structures given a bit mask of
+// video standards to support.  The array is allocated from the heap, and
+// the number of elements is returned in the first argument.
+struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
+                                          v4l2_std_id id);
+
+// Return mask of which video standard bits are valid
+v4l2_std_id pvr2_std_get_usable(void);
+
+#endif /* __PVRUSB2_STD_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
new file mode 100644 (file)
index 0000000..c6e6523
--- /dev/null
@@ -0,0 +1,865 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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/string.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include "pvrusb2-sysfs.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-debug.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+#include "pvrusb2-debugifc.h"
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+#define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__)
+
+struct pvr2_sysfs {
+       struct pvr2_channel channel;
+       struct class_device *class_dev;
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+       struct pvr2_sysfs_debugifc *debugifc;
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+       struct pvr2_sysfs_ctl_item *item_first;
+       struct pvr2_sysfs_ctl_item *item_last;
+       struct sysfs_ops kops;
+       struct kobj_type ktype;
+       struct class_device_attribute attr_v4l_minor_number;
+       struct class_device_attribute attr_unit_number;
+};
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+struct pvr2_sysfs_debugifc {
+       struct class_device_attribute attr_debugcmd;
+       struct class_device_attribute attr_debuginfo;
+};
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+struct pvr2_sysfs_ctl_item {
+       struct class_device_attribute attr_name;
+       struct class_device_attribute attr_type;
+       struct class_device_attribute attr_min;
+       struct class_device_attribute attr_max;
+       struct class_device_attribute attr_enum;
+       struct class_device_attribute attr_bits;
+       struct class_device_attribute attr_val;
+       struct class_device_attribute attr_custom;
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *chptr;
+       struct pvr2_sysfs_ctl_item *item_next;
+       struct attribute *attr_gen[7];
+       struct attribute_group grp;
+       char name[80];
+};
+
+struct pvr2_sysfs_class {
+       struct class class;
+};
+
+static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       const char *name;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+
+       name = pvr2_ctrl_get_desc(cptr);
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name);
+
+       if (!name) return -EINVAL;
+
+       return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+}
+
+static ssize_t show_type(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       const char *name;
+       enum pvr2_ctl_type tp;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+
+       tp = pvr2_ctrl_get_type(cptr);
+       switch (tp) {
+       case pvr2_ctl_int: name = "integer"; break;
+       case pvr2_ctl_enum: name = "enum"; break;
+       case pvr2_ctl_bitmask: name = "bitmask"; break;
+       case pvr2_ctl_bool: name = "boolean"; break;
+       default: name = "?"; break;
+       }
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name);
+
+       if (!name) return -EINVAL;
+
+       return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+}
+
+static ssize_t show_min(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       long val;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+       val = pvr2_ctrl_get_min(cptr);
+
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val);
+
+       return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
+}
+
+static ssize_t show_max(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       long val;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+       val = pvr2_ctrl_get_max(cptr);
+
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val);
+
+       return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
+}
+
+static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       int val,ret;
+       unsigned int cnt = 0;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+
+       ret = pvr2_ctrl_get_value(cptr,&val);
+       if (ret < 0) return ret;
+
+       ret = pvr2_ctrl_value_to_sym(cptr,~0,val,
+                                    buf,PAGE_SIZE-1,&cnt);
+
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)",
+                        sfp,id,cnt,buf,val);
+       buf[cnt] = '\n';
+       return cnt+1;
+}
+
+static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       int val,ret;
+       unsigned int cnt = 0;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+
+       ret = pvr2_ctrl_get_value(cptr,&val);
+       if (ret < 0) return ret;
+
+       ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val,
+                                           buf,PAGE_SIZE-1,&cnt);
+
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)",
+                        sfp,id,cnt,buf,val);
+       buf[cnt] = '\n';
+       return cnt+1;
+}
+
+static ssize_t show_enum(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       long val;
+       unsigned int bcnt,ccnt,ecnt;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+       ecnt = pvr2_ctrl_get_cnt(cptr);
+       bcnt = 0;
+       for (val = 0; val < ecnt; val++) {
+               pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+               if (!ccnt) continue;
+               bcnt += ccnt;
+               if (bcnt >= PAGE_SIZE) break;
+               buf[bcnt] = '\n';
+               bcnt++;
+       }
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id);
+       return bcnt;
+}
+
+static ssize_t show_bits(int id,struct class_device *class_dev,char *buf)
+{
+       struct pvr2_ctrl *cptr;
+       struct pvr2_sysfs *sfp;
+       int valid_bits,msk;
+       unsigned int bcnt,ccnt;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (!cptr) return -EINVAL;
+       valid_bits = pvr2_ctrl_get_mask(cptr);
+       bcnt = 0;
+       for (msk = 1; valid_bits; msk <<= 1) {
+               if (!(msk & valid_bits)) continue;
+               valid_bits &= ~msk;
+               pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+               bcnt += ccnt;
+               if (bcnt >= PAGE_SIZE) break;
+               buf[bcnt] = '\n';
+               bcnt++;
+       }
+       pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id);
+       return bcnt;
+}
+
+static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp,
+                        const char *buf,unsigned int count)
+{
+       struct pvr2_ctrl *cptr;
+       int ret;
+       int mask,val;
+
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+       if (customfl) {
+               ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val);
+       } else {
+               ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val);
+       }
+       if (ret < 0) return ret;
+       ret = pvr2_ctrl_set_mask_value(cptr,mask,val);
+       pvr2_hdw_commit_ctl(sfp->channel.hdw);
+       return ret;
+}
+
+static ssize_t store_val_norm(int id,struct class_device *class_dev,
+                            const char *buf,size_t count)
+{
+       struct pvr2_sysfs *sfp;
+       int ret;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       ret = store_val_any(id,0,sfp,buf,count);
+       if (!ret) ret = count;
+       return ret;
+}
+
+static ssize_t store_val_custom(int id,struct class_device *class_dev,
+                               const char *buf,size_t count)
+{
+       struct pvr2_sysfs *sfp;
+       int ret;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       ret = store_val_any(id,1,sfp,buf,count);
+       if (!ret) ret = count;
+       return ret;
+}
+
+/*
+  Mike Isely <isely@pobox.com> 30-April-2005
+
+  This next batch of horrible preprocessor hackery is needed because the
+  kernel's class_device_attribute mechanism fails to pass the actual
+  attribute through to the show / store functions, which means we have no
+  way to package up any attribute-specific parameters, like for example the
+  control id.  So we work around this brain-damage by encoding the control
+  id into the show / store functions themselves and pick the function based
+  on the control id we're setting up.  These macros try to ease the pain.
+  Yuck.
+*/
+
+#define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \
+static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \
+{ return sf_name(ctl_id,class_dev,buf); }
+
+#define CREATE_STORE_INSTANCE(sf_name,ctl_id) \
+static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \
+{ return sf_name(ctl_id,class_dev,buf,count); }
+
+#define CREATE_BATCH(ctl_id) \
+CREATE_SHOW_INSTANCE(show_name,ctl_id) \
+CREATE_SHOW_INSTANCE(show_type,ctl_id) \
+CREATE_SHOW_INSTANCE(show_min,ctl_id) \
+CREATE_SHOW_INSTANCE(show_max,ctl_id) \
+CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \
+CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \
+CREATE_SHOW_INSTANCE(show_enum,ctl_id) \
+CREATE_SHOW_INSTANCE(show_bits,ctl_id) \
+CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \
+CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \
+
+CREATE_BATCH(0)
+CREATE_BATCH(1)
+CREATE_BATCH(2)
+CREATE_BATCH(3)
+CREATE_BATCH(4)
+CREATE_BATCH(5)
+CREATE_BATCH(6)
+CREATE_BATCH(7)
+CREATE_BATCH(8)
+CREATE_BATCH(9)
+CREATE_BATCH(10)
+CREATE_BATCH(11)
+CREATE_BATCH(12)
+CREATE_BATCH(13)
+CREATE_BATCH(14)
+CREATE_BATCH(15)
+CREATE_BATCH(16)
+CREATE_BATCH(17)
+CREATE_BATCH(18)
+CREATE_BATCH(19)
+CREATE_BATCH(20)
+CREATE_BATCH(21)
+CREATE_BATCH(22)
+CREATE_BATCH(23)
+CREATE_BATCH(24)
+CREATE_BATCH(25)
+CREATE_BATCH(26)
+CREATE_BATCH(27)
+CREATE_BATCH(28)
+CREATE_BATCH(29)
+CREATE_BATCH(30)
+CREATE_BATCH(31)
+CREATE_BATCH(32)
+CREATE_BATCH(33)
+CREATE_BATCH(34)
+CREATE_BATCH(35)
+CREATE_BATCH(36)
+CREATE_BATCH(37)
+CREATE_BATCH(38)
+CREATE_BATCH(39)
+CREATE_BATCH(40)
+CREATE_BATCH(41)
+CREATE_BATCH(42)
+CREATE_BATCH(43)
+CREATE_BATCH(44)
+CREATE_BATCH(45)
+CREATE_BATCH(46)
+CREATE_BATCH(47)
+CREATE_BATCH(48)
+CREATE_BATCH(49)
+CREATE_BATCH(50)
+CREATE_BATCH(51)
+CREATE_BATCH(52)
+CREATE_BATCH(53)
+CREATE_BATCH(54)
+CREATE_BATCH(55)
+CREATE_BATCH(56)
+CREATE_BATCH(57)
+CREATE_BATCH(58)
+CREATE_BATCH(59)
+
+struct pvr2_sysfs_func_set {
+       ssize_t (*show_name)(struct class_device *,char *);
+       ssize_t (*show_type)(struct class_device *,char *);
+       ssize_t (*show_min)(struct class_device *,char *);
+       ssize_t (*show_max)(struct class_device *,char *);
+       ssize_t (*show_enum)(struct class_device *,char *);
+       ssize_t (*show_bits)(struct class_device *,char *);
+       ssize_t (*show_val_norm)(struct class_device *,char *);
+       ssize_t (*store_val_norm)(struct class_device *,
+                                 const char *,size_t);
+       ssize_t (*show_val_custom)(struct class_device *,char *);
+       ssize_t (*store_val_custom)(struct class_device *,
+                                   const char *,size_t);
+};
+
+#define INIT_BATCH(ctl_id) \
+[ctl_id] = { \
+    .show_name = show_name_##ctl_id, \
+    .show_type = show_type_##ctl_id, \
+    .show_min = show_min_##ctl_id, \
+    .show_max = show_max_##ctl_id, \
+    .show_enum = show_enum_##ctl_id, \
+    .show_bits = show_bits_##ctl_id, \
+    .show_val_norm = show_val_norm_##ctl_id, \
+    .store_val_norm = store_val_norm_##ctl_id, \
+    .show_val_custom = show_val_custom_##ctl_id, \
+    .store_val_custom = store_val_custom_##ctl_id, \
+} \
+
+static struct pvr2_sysfs_func_set funcs[] = {
+       INIT_BATCH(0),
+       INIT_BATCH(1),
+       INIT_BATCH(2),
+       INIT_BATCH(3),
+       INIT_BATCH(4),
+       INIT_BATCH(5),
+       INIT_BATCH(6),
+       INIT_BATCH(7),
+       INIT_BATCH(8),
+       INIT_BATCH(9),
+       INIT_BATCH(10),
+       INIT_BATCH(11),
+       INIT_BATCH(12),
+       INIT_BATCH(13),
+       INIT_BATCH(14),
+       INIT_BATCH(15),
+       INIT_BATCH(16),
+       INIT_BATCH(17),
+       INIT_BATCH(18),
+       INIT_BATCH(19),
+       INIT_BATCH(20),
+       INIT_BATCH(21),
+       INIT_BATCH(22),
+       INIT_BATCH(23),
+       INIT_BATCH(24),
+       INIT_BATCH(25),
+       INIT_BATCH(26),
+       INIT_BATCH(27),
+       INIT_BATCH(28),
+       INIT_BATCH(29),
+       INIT_BATCH(30),
+       INIT_BATCH(31),
+       INIT_BATCH(32),
+       INIT_BATCH(33),
+       INIT_BATCH(34),
+       INIT_BATCH(35),
+       INIT_BATCH(36),
+       INIT_BATCH(37),
+       INIT_BATCH(38),
+       INIT_BATCH(39),
+       INIT_BATCH(40),
+       INIT_BATCH(41),
+       INIT_BATCH(42),
+       INIT_BATCH(43),
+       INIT_BATCH(44),
+       INIT_BATCH(45),
+       INIT_BATCH(46),
+       INIT_BATCH(47),
+       INIT_BATCH(48),
+       INIT_BATCH(49),
+       INIT_BATCH(50),
+       INIT_BATCH(51),
+       INIT_BATCH(52),
+       INIT_BATCH(53),
+       INIT_BATCH(54),
+       INIT_BATCH(55),
+       INIT_BATCH(56),
+       INIT_BATCH(57),
+       INIT_BATCH(58),
+       INIT_BATCH(59),
+};
+
+
+static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
+{
+       struct pvr2_sysfs_ctl_item *cip;
+       struct pvr2_sysfs_func_set *fp;
+       struct pvr2_ctrl *cptr;
+       unsigned int cnt,acnt;
+
+       if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
+               return;
+       }
+
+       fp = funcs + ctl_id;
+       cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
+       if (!cptr) return;
+
+       cip = kmalloc(sizeof(*cip),GFP_KERNEL);
+       if (!cip) return;
+       memset(cip,0,sizeof(*cip));
+       pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
+
+       cip->cptr = cptr;
+
+       cip->chptr = sfp;
+       cip->item_next = 0;
+       if (sfp->item_last) {
+               sfp->item_last->item_next = cip;
+       } else {
+               sfp->item_first = cip;
+       }
+       sfp->item_last = cip;
+
+       cip->attr_name.attr.owner = THIS_MODULE;
+       cip->attr_name.attr.name = "name";
+       cip->attr_name.attr.mode = S_IRUGO;
+       cip->attr_name.show = fp->show_name;
+
+       cip->attr_type.attr.owner = THIS_MODULE;
+       cip->attr_type.attr.name = "type";
+       cip->attr_type.attr.mode = S_IRUGO;
+       cip->attr_type.show = fp->show_type;
+
+       cip->attr_min.attr.owner = THIS_MODULE;
+       cip->attr_min.attr.name = "min_val";
+       cip->attr_min.attr.mode = S_IRUGO;
+       cip->attr_min.show = fp->show_min;
+
+       cip->attr_max.attr.owner = THIS_MODULE;
+       cip->attr_max.attr.name = "max_val";
+       cip->attr_max.attr.mode = S_IRUGO;
+       cip->attr_max.show = fp->show_max;
+
+       cip->attr_val.attr.owner = THIS_MODULE;
+       cip->attr_val.attr.name = "cur_val";
+       cip->attr_val.attr.mode = S_IRUGO;
+
+       cip->attr_custom.attr.owner = THIS_MODULE;
+       cip->attr_custom.attr.name = "custom_val";
+       cip->attr_custom.attr.mode = S_IRUGO;
+
+       cip->attr_enum.attr.owner = THIS_MODULE;
+       cip->attr_enum.attr.name = "enum_val";
+       cip->attr_enum.attr.mode = S_IRUGO;
+       cip->attr_enum.show = fp->show_enum;
+
+       cip->attr_bits.attr.owner = THIS_MODULE;
+       cip->attr_bits.attr.name = "bit_val";
+       cip->attr_bits.attr.mode = S_IRUGO;
+       cip->attr_bits.show = fp->show_bits;
+
+       if (pvr2_ctrl_is_writable(cptr)) {
+               cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP;
+               cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP;
+       }
+
+       acnt = 0;
+       cip->attr_gen[acnt++] = &cip->attr_name.attr;
+       cip->attr_gen[acnt++] = &cip->attr_type.attr;
+       cip->attr_gen[acnt++] = &cip->attr_val.attr;
+       cip->attr_val.show = fp->show_val_norm;
+       cip->attr_val.store = fp->store_val_norm;
+       if (pvr2_ctrl_has_custom_symbols(cptr)) {
+               cip->attr_gen[acnt++] = &cip->attr_custom.attr;
+               cip->attr_custom.show = fp->show_val_custom;
+               cip->attr_custom.store = fp->store_val_custom;
+       }
+       switch (pvr2_ctrl_get_type(cptr)) {
+       case pvr2_ctl_enum:
+               // Control is an enumeration
+               cip->attr_gen[acnt++] = &cip->attr_enum.attr;
+               break;
+       case pvr2_ctl_int:
+               // Control is an integer
+               cip->attr_gen[acnt++] = &cip->attr_min.attr;
+               cip->attr_gen[acnt++] = &cip->attr_max.attr;
+               break;
+       case pvr2_ctl_bitmask:
+               // Control is an bitmask
+               cip->attr_gen[acnt++] = &cip->attr_bits.attr;
+               break;
+       default: break;
+       }
+
+       cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s",
+                       pvr2_ctrl_get_name(cptr));
+       cip->name[cnt] = 0;
+       cip->grp.name = cip->name;
+       cip->grp.attrs = cip->attr_gen;
+
+       sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
+}
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+static ssize_t debuginfo_show(struct class_device *,char *);
+static ssize_t debugcmd_show(struct class_device *,char *);
+static ssize_t debugcmd_store(struct class_device *,const char *,size_t count);
+
+static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
+{
+       struct pvr2_sysfs_debugifc *dip;
+       dip = kmalloc(sizeof(*dip),GFP_KERNEL);
+       if (!dip) return;
+       memset(dip,0,sizeof(*dip));
+       dip->attr_debugcmd.attr.owner = THIS_MODULE;
+       dip->attr_debugcmd.attr.name = "debugcmd";
+       dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;
+       dip->attr_debugcmd.show = debugcmd_show;
+       dip->attr_debugcmd.store = debugcmd_store;
+       dip->attr_debuginfo.attr.owner = THIS_MODULE;
+       dip->attr_debuginfo.attr.name = "debuginfo";
+       dip->attr_debuginfo.attr.mode = S_IRUGO;
+       dip->attr_debuginfo.show = debuginfo_show;
+       sfp->debugifc = dip;
+       class_device_create_file(sfp->class_dev,&dip->attr_debugcmd);
+       class_device_create_file(sfp->class_dev,&dip->attr_debuginfo);
+}
+
+
+static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)
+{
+       if (!sfp->debugifc) return;
+       class_device_remove_file(sfp->class_dev,
+                                &sfp->debugifc->attr_debuginfo);
+       class_device_remove_file(sfp->class_dev,&sfp->debugifc->attr_debugcmd);
+       kfree(sfp->debugifc);
+       sfp->debugifc = 0;
+}
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+
+static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp)
+{
+       unsigned int idx,cnt;
+       cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw);
+       for (idx = 0; idx < cnt; idx++) {
+               pvr2_sysfs_add_control(sfp,idx);
+       }
+}
+
+
+static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp)
+{
+       struct pvr2_sysfs_ctl_item *cip1,*cip2;
+       for (cip1 = sfp->item_first; cip1; cip1 = cip2) {
+               cip2 = cip1->item_next;
+               sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp);
+               pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1);
+               kfree(cip1);
+       }
+}
+
+
+static void pvr2_sysfs_class_release(struct class *class)
+{
+       struct pvr2_sysfs_class *clp;
+       clp = container_of(class,struct pvr2_sysfs_class,class);
+       pvr2_sysfs_trace("Destroying pvr2_sysfs_class id=%p",clp);
+       kfree(clp);
+}
+
+
+static void pvr2_sysfs_release(struct class_device *class_dev)
+{
+       pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev);
+       kfree(class_dev);
+}
+
+
+static void class_dev_destroy(struct pvr2_sysfs *sfp)
+{
+       if (!sfp->class_dev) return;
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+       pvr2_sysfs_tear_down_debugifc(sfp);
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+       pvr2_sysfs_tear_down_controls(sfp);
+       class_device_remove_file(sfp->class_dev,&sfp->attr_v4l_minor_number);
+       class_device_remove_file(sfp->class_dev,&sfp->attr_unit_number);
+       pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
+       sfp->class_dev->class_data = 0;
+       class_device_unregister(sfp->class_dev);
+       sfp->class_dev = 0;
+}
+
+
+static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       return scnprintf(buf,PAGE_SIZE,"%d\n",
+                        pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw));
+}
+
+
+static ssize_t unit_number_show(struct class_device *class_dev,char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       return scnprintf(buf,PAGE_SIZE,"%d\n",
+                        pvr2_hdw_get_unit_number(sfp->channel.hdw));
+}
+
+
+static void class_dev_create(struct pvr2_sysfs *sfp,
+                            struct pvr2_sysfs_class *class_ptr)
+{
+       struct usb_device *usb_dev;
+       struct class_device *class_dev;
+       usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
+       if (!usb_dev) return;
+       class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL);
+       if (!class_dev) return;
+       memset(class_dev,0,sizeof(*class_dev));
+
+       pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
+
+       class_dev->class = &class_ptr->class;
+       if (pvr2_hdw_get_sn(sfp->channel.hdw)) {
+               snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu",
+                        pvr2_hdw_get_sn(sfp->channel.hdw));
+       } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) {
+               snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c",
+                        pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a');
+       } else {
+               kfree(class_dev);
+               return;
+       }
+
+       class_dev->dev = &usb_dev->dev;
+
+       sfp->class_dev = class_dev;
+       class_dev->class_data = sfp;
+       class_device_register(class_dev);
+
+       sfp->attr_v4l_minor_number.attr.owner = THIS_MODULE;
+       sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number";
+       sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;
+       sfp->attr_v4l_minor_number.show = v4l_minor_number_show;
+       sfp->attr_v4l_minor_number.store = 0;
+       class_device_create_file(sfp->class_dev,&sfp->attr_v4l_minor_number);
+       sfp->attr_unit_number.attr.owner = THIS_MODULE;
+       sfp->attr_unit_number.attr.name = "unit_number";
+       sfp->attr_unit_number.attr.mode = S_IRUGO;
+       sfp->attr_unit_number.show = unit_number_show;
+       sfp->attr_unit_number.store = 0;
+       class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
+
+       pvr2_sysfs_add_controls(sfp);
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+       pvr2_sysfs_add_debugifc(sfp);
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+}
+
+
+static void pvr2_sysfs_internal_check(struct pvr2_channel *chp)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = container_of(chp,struct pvr2_sysfs,channel);
+       if (!sfp->channel.mc_head->disconnect_flag) return;
+       pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp);
+       class_dev_destroy(sfp);
+       pvr2_channel_done(&sfp->channel);
+       kfree(sfp);
+}
+
+
+struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
+                                    struct pvr2_sysfs_class *class_ptr)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = kmalloc(sizeof(*sfp),GFP_KERNEL);
+       if (!sfp) return sfp;
+       memset(sfp,0,sizeof(*sfp));
+       pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);
+       pvr2_channel_init(&sfp->channel,mp);
+       sfp->channel.check_func = pvr2_sysfs_internal_check;
+
+       class_dev_create(sfp,class_ptr);
+       return sfp;
+}
+
+
+static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
+                             int numenvp,char *buf,int size)
+{
+       /* Even though we don't do anything here, we still need this function
+          because sysfs will still try to call it. */
+       return 0;
+}
+
+struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
+{
+       struct pvr2_sysfs_class *clp;
+       clp = kmalloc(sizeof(*clp),GFP_KERNEL);
+       if (!clp) return clp;
+       memset(clp,0,sizeof(*clp));
+       pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
+       clp->class.name = "pvrusb2";
+       clp->class.class_release = pvr2_sysfs_class_release;
+       clp->class.release = pvr2_sysfs_release;
+       clp->class.uevent = pvr2_sysfs_hotplug;
+       if (class_register(&clp->class)) {
+               pvr2_sysfs_trace(
+                       "Registration failed for pvr2_sysfs_class id=%p",clp);
+               kfree(clp);
+               clp = 0;
+       }
+       return clp;
+}
+
+
+void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp)
+{
+       class_unregister(&clp->class);
+}
+
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+static ssize_t debuginfo_show(struct class_device *class_dev,char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       pvr2_hdw_trigger_module_log(sfp->channel.hdw);
+       return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);
+}
+
+
+static ssize_t debugcmd_show(struct class_device *class_dev,char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);
+}
+
+
+static ssize_t debugcmd_store(struct class_device *class_dev,
+                             const char *buf,size_t count)
+{
+       struct pvr2_sysfs *sfp;
+       int ret;
+
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+
+       ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);
+       if (ret < 0) return ret;
+       return count;
+}
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.h b/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
new file mode 100644 (file)
index 0000000..ff9373b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_SYSFS_H
+#define __PVRUSB2_SYSFS_H
+
+#include <linux/list.h>
+#include <linux/sysfs.h>
+#include "pvrusb2-context.h"
+
+struct pvr2_sysfs;
+struct pvr2_sysfs_class;
+
+struct pvr2_sysfs_class *pvr2_sysfs_class_create(void);
+void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *);
+
+struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *,
+                                    struct pvr2_sysfs_class *);
+
+#endif /* __PVRUSB2_SYSFS_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
new file mode 100644 (file)
index 0000000..f4aba81
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2.h"
+#include "pvrusb2-util.h"
+#include "pvrusb2-tuner.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+
+struct pvr2_tuner_handler {
+       struct pvr2_hdw *hdw;
+       struct pvr2_i2c_client *client;
+       struct pvr2_i2c_handler i2c_handler;
+       int type_update_fl;
+};
+
+
+static void set_type(struct pvr2_tuner_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       struct tuner_setup setup;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c tuner set_type(%d)",hdw->tuner_type);
+       if (((int)(hdw->tuner_type)) < 0) return;
+
+       setup.addr = ADDR_UNSET;
+       setup.type = hdw->tuner_type;
+       setup.mode_mask = T_RADIO | T_ANALOG_TV;
+       /* We may really want mode_mask to be T_ANALOG_TV for now */
+       pvr2_i2c_client_cmd(ctxt->client,TUNER_SET_TYPE_ADDR,&setup);
+       ctxt->type_update_fl = 0;
+}
+
+
+static int tuner_check(struct pvr2_tuner_handler *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       if (hdw->tuner_updated) ctxt->type_update_fl = !0;
+       return ctxt->type_update_fl != 0;
+}
+
+
+static void tuner_update(struct pvr2_tuner_handler *ctxt)
+{
+       if (ctxt->type_update_fl) set_type(ctxt);
+}
+
+
+static void pvr2_tuner_detach(struct pvr2_tuner_handler *ctxt)
+{
+       ctxt->client->handler = 0;
+       kfree(ctxt);
+}
+
+
+static unsigned int pvr2_tuner_describe(struct pvr2_tuner_handler *ctxt,char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-tuner");
+}
+
+
+const static struct pvr2_i2c_handler_functions tuner_funcs = {
+       .detach = (void (*)(void *))pvr2_tuner_detach,
+       .check = (int (*)(void *))tuner_check,
+       .update = (void (*)(void *))tuner_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_tuner_describe,
+};
+
+
+int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+       struct pvr2_tuner_handler *ctxt;
+       if (cp->handler) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->i2c_handler.func_data = ctxt;
+       ctxt->i2c_handler.func_table = &tuner_funcs;
+       ctxt->type_update_fl = !0;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       cp->handler = &ctxt->i2c_handler;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x tuner handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.h b/drivers/media/video/pvrusb2/pvrusb2-tuner.h
new file mode 100644 (file)
index 0000000..556f12a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_TUNER_H
+#define __PVRUSB2_TUNER_H
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_tuner_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+#endif /* __PVRUSB2_TUNER_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-util.h b/drivers/media/video/pvrusb2/pvrusb2-util.h
new file mode 100644 (file)
index 0000000..e53aee4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_UTIL_H
+#define __PVRUSB2_UTIL_H
+
+#define PVR2_DECOMPOSE_LE(t,i,d) \
+    do {    \
+       (t)[i] = (d) & 0xff;\
+       (t)[i+1] = ((d) >> 8) & 0xff;\
+       (t)[i+2] = ((d) >> 16) & 0xff;\
+       (t)[i+3] = ((d) >> 24) & 0xff;\
+    } while(0)
+
+#define PVR2_DECOMPOSE_BE(t,i,d) \
+    do {    \
+       (t)[i+3] = (d) & 0xff;\
+       (t)[i+2] = ((d) >> 8) & 0xff;\
+       (t)[i+1] = ((d) >> 16) & 0xff;\
+       (t)[i] = ((d) >> 24) & 0xff;\
+    } while(0)
+
+#define PVR2_COMPOSE_LE(t,i) \
+    ((((u32)((t)[i+3])) << 24) | \
+     (((u32)((t)[i+2])) << 16) | \
+     (((u32)((t)[i+1])) << 8) | \
+     ((u32)((t)[i])))
+
+#define PVR2_COMPOSE_BE(t,i) \
+    ((((u32)((t)[i])) << 24) | \
+     (((u32)((t)[i+1])) << 16) | \
+     (((u32)((t)[i+2])) << 8) | \
+     ((u32)((t)[i+3])))
+
+
+#endif /* __PVRUSB2_UTIL_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
new file mode 100644 (file)
index 0000000..9619510
--- /dev/null
@@ -0,0 +1,1126 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include "pvrusb2-context.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-v4l2.h"
+#include "pvrusb2-ioread.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+struct pvr2_v4l2_dev;
+struct pvr2_v4l2_fh;
+struct pvr2_v4l2;
+
+/* V4L no longer provide the ability to set / get a private context pointer
+   (i.e. video_get_drvdata / video_set_drvdata), which means we have to
+   concoct our own context locating mechanism.  Supposedly this is intended
+   to simplify driver implementation.  It's not clear to me how that can
+   possibly be true.  Our solution here is to maintain a lookup table of
+   our context instances, indexed by the minor device number of the V4L
+   device.  See pvr2_v4l2_open() for some implications of this approach. */
+static struct pvr2_v4l2_dev *devices[256];
+static DEFINE_MUTEX(device_lock);
+
+struct pvr2_v4l2_dev {
+       struct pvr2_v4l2 *v4lp;
+       struct video_device *vdev;
+       struct pvr2_context_stream *stream;
+       int ctxt_idx;
+       enum pvr2_config config;
+};
+
+struct pvr2_v4l2_fh {
+       struct pvr2_channel channel;
+       struct pvr2_v4l2_dev *dev_info;
+       enum v4l2_priority prio;
+       struct pvr2_ioread *rhp;
+       struct file *file;
+       struct pvr2_v4l2 *vhead;
+       struct pvr2_v4l2_fh *vnext;
+       struct pvr2_v4l2_fh *vprev;
+       wait_queue_head_t wait_data;
+       int fw_mode_flag;
+};
+
+struct pvr2_v4l2 {
+       struct pvr2_channel channel;
+       struct pvr2_v4l2_fh *vfirst;
+       struct pvr2_v4l2_fh *vlast;
+
+       struct v4l2_prio_state prio;
+
+       /* streams */
+       struct pvr2_v4l2_dev video_dev;
+};
+
+static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "Offset for device's minor");
+
+struct v4l2_capability pvr_capability ={
+       .driver         = "pvrusb2",
+       .card           = "Hauppauge WinTV pvr-usb2",
+       .bus_info       = "usb",
+       .version        = KERNEL_VERSION(0,8,0),
+       .capabilities   = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
+                          V4L2_CAP_TUNER | V4L2_CAP_AUDIO |
+                          V4L2_CAP_READWRITE),
+       .reserved       = {0,0,0,0}
+};
+
+static struct v4l2_tuner pvr_v4l2_tuners[]= {
+       {
+               .index      = 0,
+               .name       = "TV Tuner",
+               .type           = V4L2_TUNER_ANALOG_TV,
+               .capability     = (V4L2_TUNER_CAP_NORM |
+                                  V4L2_TUNER_CAP_STEREO |
+                                  V4L2_TUNER_CAP_LANG1 |
+                                  V4L2_TUNER_CAP_LANG2),
+               .rangelow   = 0,
+               .rangehigh  = 0,
+               .rxsubchans     = V4L2_TUNER_SUB_STEREO,
+               .audmode        = V4L2_TUNER_MODE_STEREO,
+               .signal         = 0,
+               .afc            = 0,
+               .reserved       = {0,0,0,0}
+       }
+};
+
+struct v4l2_fmtdesc pvr_fmtdesc [] = {
+       {
+               .index          = 0,
+               .type           = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               .flags          = V4L2_FMT_FLAG_COMPRESSED,
+               .description    = "MPEG1/2",
+               // This should really be V4L2_PIX_FMT_MPEG, but xawtv
+               // breaks when I do that.
+               .pixelformat    = 0, // V4L2_PIX_FMT_MPEG,
+               .reserved       = { 0, 0, 0, 0 }
+       }
+};
+
+#define PVR_FORMAT_PIX  0
+#define PVR_FORMAT_VBI  1
+
+struct v4l2_format pvr_format [] = {
+       [PVR_FORMAT_PIX] = {
+               .type   = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               .fmt    = {
+                       .pix        = {
+                               .width          = 720,
+                               .height             = 576,
+                               // This should really be V4L2_PIX_FMT_MPEG,
+                               // but xawtv breaks when I do that.
+                               .pixelformat    = 0, // V4L2_PIX_FMT_MPEG,
+                               .field          = V4L2_FIELD_INTERLACED,
+                               .bytesperline   = 0,  // doesn't make sense
+                                                     // here
+                               //FIXME : Don't know what to put here...
+                               .sizeimage          = (32*1024),
+                               .colorspace     = 0, // doesn't make sense here
+                               .priv           = 0
+                       }
+               }
+       },
+       [PVR_FORMAT_VBI] = {
+               .type   = V4L2_BUF_TYPE_VBI_CAPTURE,
+               .fmt    = {
+                       .vbi        = {
+                               .sampling_rate = 27000000,
+                               .offset = 248,
+                               .samples_per_line = 1443,
+                               .sample_format = V4L2_PIX_FMT_GREY,
+                               .start = { 0, 0 },
+                               .count = { 0, 0 },
+                               .flags = 0,
+                               .reserved = { 0, 0 }
+                       }
+               }
+       }
+};
+
+/*
+ * pvr_ioctl()
+ *
+ * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
+ *
+ */
+static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
+                             unsigned int cmd, void *arg)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       struct pvr2_v4l2 *vp = fh->vhead;
+       struct pvr2_v4l2_dev *dev_info = fh->dev_info;
+       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+       int ret = -EINVAL;
+
+       if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+               v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
+       }
+
+       if (!pvr2_hdw_dev_ok(hdw)) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "ioctl failed - bad or no context");
+               return -EFAULT;
+       }
+
+       /* check priority */
+       switch (cmd) {
+       case VIDIOC_S_CTRL:
+       case VIDIOC_S_STD:
+       case VIDIOC_S_INPUT:
+       case VIDIOC_S_TUNER:
+       case VIDIOC_S_FREQUENCY:
+               ret = v4l2_prio_check(&vp->prio, &fh->prio);
+               if (ret)
+                       return ret;
+       }
+
+       switch (cmd) {
+       case VIDIOC_QUERYCAP:
+       {
+               struct v4l2_capability *cap = arg;
+
+               memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+
+               ret = 0;
+               break;
+       }
+
+       case VIDIOC_G_PRIORITY:
+       {
+               enum v4l2_priority *p = arg;
+
+               *p = v4l2_prio_max(&vp->prio);
+               ret = 0;
+               break;
+       }
+
+       case VIDIOC_S_PRIORITY:
+       {
+               enum v4l2_priority *prio = arg;
+
+               ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
+               break;
+       }
+
+       case VIDIOC_ENUMSTD:
+       {
+               struct v4l2_standard *vs = (struct v4l2_standard *)arg;
+               int idx = vs->index;
+               ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
+               break;
+       }
+
+       case VIDIOC_G_STD:
+       {
+               int val = 0;
+               ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
+               *(v4l2_std_id *)arg = val;
+               break;
+       }
+
+       case VIDIOC_S_STD:
+       {
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
+                       *(v4l2_std_id *)arg);
+               break;
+       }
+
+       case VIDIOC_ENUMINPUT:
+       {
+               struct pvr2_ctrl *cptr;
+               struct v4l2_input *vi = (struct v4l2_input *)arg;
+               struct v4l2_input tmp;
+               unsigned int cnt;
+
+               cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+
+               memset(&tmp,0,sizeof(tmp));
+               tmp.index = vi->index;
+               ret = 0;
+               switch (vi->index) {
+               case PVR2_CVAL_INPUT_TV:
+               case PVR2_CVAL_INPUT_RADIO:
+                       tmp.type = V4L2_INPUT_TYPE_TUNER;
+                       break;
+               case PVR2_CVAL_INPUT_SVIDEO:
+               case PVR2_CVAL_INPUT_COMPOSITE:
+                       tmp.type = V4L2_INPUT_TYPE_CAMERA;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+               if (ret < 0) break;
+
+               cnt = 0;
+               pvr2_ctrl_get_valname(cptr,vi->index,
+                                     tmp.name,sizeof(tmp.name)-1,&cnt);
+               tmp.name[cnt] = 0;
+
+               /* Don't bother with audioset, since this driver currently
+                  always switches the audio whenever the video is
+                  switched. */
+
+               /* Handling std is a tougher problem.  It doesn't make
+                  sense in cases where a device might be multi-standard.
+                  We could just copy out the current value for the
+                  standard, but it can change over time.  For now just
+                  leave it zero. */
+
+               memcpy(vi, &tmp, sizeof(tmp));
+
+               ret = 0;
+               break;
+       }
+
+       case VIDIOC_G_INPUT:
+       {
+               struct pvr2_ctrl *cptr;
+               struct v4l2_input *vi = (struct v4l2_input *)arg;
+               int val;
+               cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+               val = 0;
+               ret = pvr2_ctrl_get_value(cptr,&val);
+               vi->index = val;
+               break;
+       }
+
+       case VIDIOC_S_INPUT:
+       {
+               struct v4l2_input *vi = (struct v4l2_input *)arg;
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+                       vi->index);
+               break;
+       }
+
+       case VIDIOC_ENUMAUDIO:
+       {
+               ret = -EINVAL;
+               break;
+       }
+
+       case VIDIOC_G_AUDIO:
+       {
+               ret = -EINVAL;
+               break;
+       }
+
+       case VIDIOC_S_AUDIO:
+       {
+               ret = -EINVAL;
+               break;
+       }
+       case VIDIOC_G_TUNER:
+       {
+               struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+               unsigned int status_mask;
+               int val;
+               if (vt->index !=0) break;
+
+               status_mask = pvr2_hdw_get_signal_status(hdw);
+
+               memcpy(vt, &pvr_v4l2_tuners[vt->index],
+                      sizeof(struct v4l2_tuner));
+
+               vt->signal = 0;
+               if (status_mask & PVR2_SIGNAL_OK) {
+                       if (status_mask & PVR2_SIGNAL_STEREO) {
+                               vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       } else {
+                               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+                       }
+                       if (status_mask & PVR2_SIGNAL_SAP) {
+                               vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 |
+                                                  V4L2_TUNER_SUB_LANG2);
+                       }
+                       vt->signal = 65535;
+               }
+
+               val = 0;
+               ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
+                       &val);
+               vt->audmode = val;
+               break;
+       }
+
+       case VIDIOC_S_TUNER:
+       {
+               struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
+
+               if (vt->index != 0)
+                       break;
+
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
+                       vt->audmode);
+       }
+
+       case VIDIOC_S_FREQUENCY:
+       {
+               const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
+               ret = pvr2_ctrl_set_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
+                       vf->frequency * 62500);
+               break;
+       }
+
+       case VIDIOC_G_FREQUENCY:
+       {
+               struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
+               int val = 0;
+               ret = pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
+                       &val);
+               val /= 62500;
+               vf->frequency = val;
+               break;
+       }
+
+       case VIDIOC_ENUM_FMT:
+       {
+               struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
+
+               /* Only one format is supported : mpeg.*/
+               if (fd->index != 0)
+                       break;
+
+               memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
+               ret = 0;
+               break;
+       }
+
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *vf = (struct v4l2_format *)arg;
+               int val;
+               switch(vf->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+                              sizeof(struct v4l2_format));
+                       val = 0;
+                       pvr2_ctrl_get_value(
+                               pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
+                               &val);
+                       vf->fmt.pix.width = val;
+                       val = 0;
+                       pvr2_ctrl_get_value(
+                               pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
+                               &val);
+                       vf->fmt.pix.height = val;
+                       ret = 0;
+                       break;
+               case V4L2_BUF_TYPE_VBI_CAPTURE:
+                       // ????? Still need to figure out to do VBI correctly
+                       ret = -EINVAL;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+               break;
+       }
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *vf = (struct v4l2_format *)arg;
+
+               ret = 0;
+               switch(vf->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+                       int h = vf->fmt.pix.height;
+                       int w = vf->fmt.pix.width;
+
+                       if (h < 200) {
+                               h = 200;
+                       } else if (h > 625) {
+                               h = 625;
+                       }
+                       if (w < 320) {
+                               w = 320;
+                       } else if (w > 720) {
+                               w = 720;
+                       }
+
+                       memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+                              sizeof(struct v4l2_format));
+                       vf->fmt.pix.width = w;
+                       vf->fmt.pix.height = h;
+
+                       if (cmd == VIDIOC_S_FMT) {
+                               pvr2_ctrl_set_value(
+                                       pvr2_hdw_get_ctrl_by_id(hdw,
+                                                               PVR2_CID_HRES),
+                                       vf->fmt.pix.width);
+                               pvr2_ctrl_set_value(
+                                       pvr2_hdw_get_ctrl_by_id(hdw,
+                                                               PVR2_CID_VRES),
+                                       vf->fmt.pix.height);
+                       }
+               } break;
+               case V4L2_BUF_TYPE_VBI_CAPTURE:
+                       // ????? Still need to figure out to do VBI correctly
+                       ret = -EINVAL;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+               break;
+       }
+
+       case VIDIOC_STREAMON:
+       {
+               ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
+               if (ret < 0) return ret;
+               ret = pvr2_hdw_set_streaming(hdw,!0);
+               break;
+       }
+
+       case VIDIOC_STREAMOFF:
+       {
+               ret = pvr2_hdw_set_streaming(hdw,0);
+               break;
+       }
+
+       case VIDIOC_QUERYCTRL:
+       {
+               struct pvr2_ctrl *cptr;
+               struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
+               ret = 0;
+               if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+                       cptr = pvr2_hdw_get_ctrl_nextv4l(
+                               hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
+                       if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
+               } else {
+                       cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
+               }
+               if (!cptr) {
+                       pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                                  "QUERYCTRL id=0x%x not implemented here",
+                                  vc->id);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                          "QUERYCTRL id=0x%x mapping name=%s (%s)",
+                          vc->id,pvr2_ctrl_get_name(cptr),
+                          pvr2_ctrl_get_desc(cptr));
+               strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
+               vc->flags = pvr2_ctrl_get_v4lflags(cptr);
+               vc->default_value = pvr2_ctrl_get_def(cptr);
+               switch (pvr2_ctrl_get_type(cptr)) {
+               case pvr2_ctl_enum:
+                       vc->type = V4L2_CTRL_TYPE_MENU;
+                       vc->minimum = 0;
+                       vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
+                       vc->step = 1;
+                       break;
+               case pvr2_ctl_bool:
+                       vc->type = V4L2_CTRL_TYPE_BOOLEAN;
+                       vc->minimum = 0;
+                       vc->maximum = 1;
+                       vc->step = 1;
+                       break;
+               case pvr2_ctl_int:
+                       vc->type = V4L2_CTRL_TYPE_INTEGER;
+                       vc->minimum = pvr2_ctrl_get_min(cptr);
+                       vc->maximum = pvr2_ctrl_get_max(cptr);
+                       vc->step = 1;
+                       break;
+               default:
+                       pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                                  "QUERYCTRL id=0x%x name=%s not mappable",
+                                  vc->id,pvr2_ctrl_get_name(cptr));
+                       ret = -EINVAL;
+                       break;
+               }
+               break;
+       }
+
+       case VIDIOC_QUERYMENU:
+       {
+               struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
+               unsigned int cnt = 0;
+               ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
+                                           vm->index,
+                                           vm->name,sizeof(vm->name)-1,
+                                           &cnt);
+               vm->name[cnt] = 0;
+               break;
+       }
+
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *vc = (struct v4l2_control *)arg;
+               int val = 0;
+               ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
+                                         &val);
+               vc->value = val;
+               break;
+       }
+
+       case VIDIOC_S_CTRL:
+       {
+               struct v4l2_control *vc = (struct v4l2_control *)arg;
+               ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
+                                         vc->value);
+               break;
+       }
+
+       case VIDIOC_G_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *ctls =
+                       (struct v4l2_ext_controls *)arg;
+               struct v4l2_ext_control *ctrl;
+               unsigned int idx;
+               int val;
+               for (idx = 0; idx < ctls->count; idx++) {
+                       ctrl = ctls->controls + idx;
+                       ret = pvr2_ctrl_get_value(
+                               pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
+                       if (ret) {
+                               ctls->error_idx = idx;
+                               break;
+                       }
+                       /* Ensure that if read as a 64 bit value, the user
+                          will still get a hopefully sane value */
+                       ctrl->value64 = 0;
+                       ctrl->value = val;
+               }
+               break;
+       }
+
+       case VIDIOC_S_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *ctls =
+                       (struct v4l2_ext_controls *)arg;
+               struct v4l2_ext_control *ctrl;
+               unsigned int idx;
+               for (idx = 0; idx < ctls->count; idx++) {
+                       ctrl = ctls->controls + idx;
+                       ret = pvr2_ctrl_set_value(
+                               pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
+                               ctrl->value);
+                       if (ret) {
+                               ctls->error_idx = idx;
+                               break;
+                       }
+               }
+               break;
+       }
+
+       case VIDIOC_TRY_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *ctls =
+                       (struct v4l2_ext_controls *)arg;
+               struct v4l2_ext_control *ctrl;
+               struct pvr2_ctrl *pctl;
+               unsigned int idx;
+               /* For the moment just validate that the requested control
+                  actually exists. */
+               for (idx = 0; idx < ctls->count; idx++) {
+                       ctrl = ctls->controls + idx;
+                       pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
+                       if (!pctl) {
+                               ret = -EINVAL;
+                               ctls->error_idx = idx;
+                               break;
+                       }
+               }
+               break;
+       }
+
+       case VIDIOC_LOG_STATUS:
+       {
+               pvr2_hdw_trigger_module_log(hdw);
+               ret = 0;
+               break;
+       }
+
+       default :
+               ret = v4l_compat_translate_ioctl(inode,file,cmd,
+                                                arg,pvr2_v4l2_do_ioctl);
+       }
+
+       pvr2_hdw_commit_ctl(hdw);
+
+       if (ret < 0) {
+               if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+                       pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                                  "pvr2_v4l2_do_ioctl failure, ret=%d",ret);
+               } else {
+                       if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+                               pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                                          "pvr2_v4l2_do_ioctl failure, ret=%d"
+                                          " command was:",ret);
+                               v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
+                                               cmd);
+                       }
+               }
+       } else {
+               pvr2_trace(PVR2_TRACE_V4LIOCTL,
+                          "pvr2_v4l2_do_ioctl complete, ret=%d (0x%x)",
+                          ret,ret);
+       }
+       return ret;
+}
+
+
+static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
+{
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "unregistering device video%d [%s]",
+                  dip->vdev->minor,pvr2_config_get_name(dip->config));
+       if (dip->ctxt_idx >= 0) {
+               mutex_lock(&device_lock);
+               devices[dip->ctxt_idx] = NULL;
+               dip->ctxt_idx = -1;
+               mutex_unlock(&device_lock);
+       }
+       video_unregister_device(dip->vdev);
+}
+
+
+static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
+{
+       pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);
+       pvr2_v4l2_dev_destroy(&vp->video_dev);
+
+       pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
+       pvr2_channel_done(&vp->channel);
+       kfree(vp);
+}
+
+
+void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
+{
+       struct pvr2_v4l2 *vp;
+       vp = container_of(chp,struct pvr2_v4l2,channel);
+       if (!vp->channel.mc_head->disconnect_flag) return;
+       if (vp->vfirst) return;
+       pvr2_v4l2_destroy_no_lock(vp);
+}
+
+
+int pvr2_v4l2_ioctl(struct inode *inode, struct file *file,
+                   unsigned int cmd, unsigned long arg)
+{
+
+/* Temporary hack : use ivtv api until a v4l2 one is available. */
+#define IVTV_IOC_G_CODEC        0xFFEE7703
+#define IVTV_IOC_S_CODEC        0xFFEE7704
+       if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0;
+       return video_usercopy(inode, file, cmd, arg, pvr2_v4l2_do_ioctl);
+}
+
+
+int pvr2_v4l2_release(struct inode *inode, struct file *file)
+{
+       struct pvr2_v4l2_fh *fhp = file->private_data;
+       struct pvr2_v4l2 *vp = fhp->vhead;
+       struct pvr2_context *mp = fhp->vhead->channel.mc_head;
+
+       pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
+
+       if (fhp->rhp) {
+               struct pvr2_stream *sp;
+               struct pvr2_hdw *hdw;
+               hdw = fhp->channel.mc_head->hdw;
+               pvr2_hdw_set_streaming(hdw,0);
+               sp = pvr2_ioread_get_stream(fhp->rhp);
+               if (sp) pvr2_stream_set_callback(sp,0,0);
+               pvr2_ioread_destroy(fhp->rhp);
+               fhp->rhp = 0;
+       }
+       v4l2_prio_close(&vp->prio, &fhp->prio);
+       file->private_data = NULL;
+
+       pvr2_context_enter(mp); do {
+               if (fhp->vnext) {
+                       fhp->vnext->vprev = fhp->vprev;
+               } else {
+                       vp->vlast = fhp->vprev;
+               }
+               if (fhp->vprev) {
+                       fhp->vprev->vnext = fhp->vnext;
+               } else {
+                       vp->vfirst = fhp->vnext;
+               }
+               fhp->vnext = 0;
+               fhp->vprev = 0;
+               fhp->vhead = 0;
+               pvr2_channel_done(&fhp->channel);
+               pvr2_trace(PVR2_TRACE_STRUCT,
+                          "Destroying pvr_v4l2_fh id=%p",fhp);
+               kfree(fhp);
+               if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
+                       pvr2_v4l2_destroy_no_lock(vp);
+               }
+       } while (0); pvr2_context_exit(mp);
+       return 0;
+}
+
+
+int pvr2_v4l2_open(struct inode *inode, struct file *file)
+{
+       struct pvr2_v4l2_dev *dip = 0; /* Our own context pointer */
+       struct pvr2_v4l2_fh *fhp;
+       struct pvr2_v4l2 *vp;
+       struct pvr2_hdw *hdw;
+
+       mutex_lock(&device_lock);
+       /* MCI 7-Jun-2006 Even though we're just doing what amounts to an
+          atomic read of the device mapping array here, we still need the
+          mutex.  The problem is that there is a tiny race possible when
+          we register the device.  We can't update the device mapping
+          array until after the device has been registered, owing to the
+          fact that we can't know the minor device number until after the
+          registration succeeds.  And if another thread tries to open the
+          device in the window of time after registration but before the
+          map is updated, then it will get back an erroneous null pointer
+          and the open will result in a spurious failure.  The only way to
+          prevent that is to (a) be inside the mutex here before we access
+          the array, and (b) cover the entire registration process later
+          on with this same mutex.  Thus if we get inside the mutex here,
+          then we can be assured that the registration process actually
+          completed correctly.  This is an unhappy complication from the
+          use of global data in a driver that lives in a preemptible
+          environment.  It sure would be nice if the video device itself
+          had a means for storing and retrieving a local context pointer.
+          Oh wait.  It did.  But now it's gone.  Silly me. */
+       {
+               unsigned int midx = iminor(file->f_dentry->d_inode);
+               if (midx < sizeof(devices)/sizeof(devices[0])) {
+                       dip = devices[midx];
+               }
+       }
+       mutex_unlock(&device_lock);
+
+       if (!dip) return -ENODEV; /* Should be impossible but I'm paranoid */
+
+       vp = dip->v4lp;
+       hdw = vp->channel.hdw;
+
+       pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");
+
+       if (!pvr2_hdw_dev_ok(hdw)) {
+               pvr2_trace(PVR2_TRACE_OPEN_CLOSE,
+                          "pvr2_v4l2_open: hardware not ready");
+               return -EIO;
+       }
+
+       fhp = kmalloc(sizeof(*fhp),GFP_KERNEL);
+       if (!fhp) {
+               return -ENOMEM;
+       }
+       memset(fhp,0,sizeof(*fhp));
+
+       init_waitqueue_head(&fhp->wait_data);
+       fhp->dev_info = dip;
+
+       pvr2_context_enter(vp->channel.mc_head); do {
+               pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
+               pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+               fhp->vnext = 0;
+               fhp->vprev = vp->vlast;
+               if (vp->vlast) {
+                       vp->vlast->vnext = fhp;
+               } else {
+                       vp->vfirst = fhp;
+               }
+               vp->vlast = fhp;
+               fhp->vhead = vp;
+       } while (0); pvr2_context_exit(vp->channel.mc_head);
+
+       fhp->file = file;
+       file->private_data = fhp;
+       v4l2_prio_open(&vp->prio,&fhp->prio);
+
+       fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
+
+       return 0;
+}
+
+
+static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp)
+{
+       wake_up(&fhp->wait_data);
+}
+
+static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
+{
+       int ret;
+       struct pvr2_stream *sp;
+       struct pvr2_hdw *hdw;
+       if (fh->rhp) return 0;
+
+       /* First read() attempt.  Try to claim the stream and start
+          it... */
+       if ((ret = pvr2_channel_claim_stream(&fh->channel,
+                                            fh->dev_info->stream)) != 0) {
+               /* Someone else must already have it */
+               return ret;
+       }
+
+       fh->rhp = pvr2_channel_create_mpeg_stream(fh->dev_info->stream);
+       if (!fh->rhp) {
+               pvr2_channel_claim_stream(&fh->channel,0);
+               return -ENOMEM;
+       }
+
+       hdw = fh->channel.mc_head->hdw;
+       sp = fh->dev_info->stream->stream;
+       pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
+       pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
+       pvr2_hdw_set_streaming(hdw,!0);
+       ret = pvr2_ioread_set_enabled(fh->rhp,!0);
+
+       return ret;
+}
+
+
+static ssize_t pvr2_v4l2_read(struct file *file,
+                             char __user *buff, size_t count, loff_t *ppos)
+{
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       int ret;
+
+       if (fh->fw_mode_flag) {
+               struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+               char *tbuf;
+               int c1,c2;
+               int tcnt = 0;
+               unsigned int offs = *ppos;
+
+               tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL);
+               if (!tbuf) return -ENOMEM;
+
+               while (count) {
+                       c1 = count;
+                       if (c1 > PAGE_SIZE) c1 = PAGE_SIZE;
+                       c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1);
+                       if (c2 < 0) {
+                               tcnt = c2;
+                               break;
+                       }
+                       if (!c2) break;
+                       if (copy_to_user(buff,tbuf,c2)) {
+                               tcnt = -EFAULT;
+                               break;
+                       }
+                       offs += c2;
+                       tcnt += c2;
+                       buff += c2;
+                       count -= c2;
+                       *ppos += c2;
+               }
+               kfree(tbuf);
+               return tcnt;
+       }
+
+       if (!fh->rhp) {
+               ret = pvr2_v4l2_iosetup(fh);
+               if (ret) {
+                       return ret;
+               }
+       }
+
+       for (;;) {
+               ret = pvr2_ioread_read(fh->rhp,buff,count);
+               if (ret >= 0) break;
+               if (ret != -EAGAIN) break;
+               if (file->f_flags & O_NONBLOCK) break;
+               /* Doing blocking I/O.  Wait here. */
+               ret = wait_event_interruptible(
+                       fh->wait_data,
+                       pvr2_ioread_avail(fh->rhp) >= 0);
+               if (ret < 0) break;
+       }
+
+       return ret;
+}
+
+
+static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask = 0;
+       struct pvr2_v4l2_fh *fh = file->private_data;
+       int ret;
+
+       if (fh->fw_mode_flag) {
+               mask |= POLLIN | POLLRDNORM;
+               return mask;
+       }
+
+       if (!fh->rhp) {
+               ret = pvr2_v4l2_iosetup(fh);
+               if (ret) return POLLERR;
+       }
+
+       poll_wait(file,&fh->wait_data,wait);
+
+       if (pvr2_ioread_avail(fh->rhp) >= 0) {
+               mask |= POLLIN | POLLRDNORM;
+       }
+
+       return mask;
+}
+
+
+static struct file_operations vdev_fops = {
+       .owner      = THIS_MODULE,
+       .open       = pvr2_v4l2_open,
+       .release    = pvr2_v4l2_release,
+       .read       = pvr2_v4l2_read,
+       .ioctl      = pvr2_v4l2_ioctl,
+       .llseek     = no_llseek,
+       .poll       = pvr2_v4l2_poll,
+};
+
+
+#define VID_HARDWARE_PVRUSB2    38  /* FIXME : need a good value */
+
+static struct video_device vdev_template = {
+       .owner      = THIS_MODULE,
+       .type       = VID_TYPE_CAPTURE | VID_TYPE_TUNER,
+       .type2      = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE
+                      | V4L2_CAP_TUNER | V4L2_CAP_AUDIO
+                      | V4L2_CAP_READWRITE),
+       .hardware   = VID_HARDWARE_PVRUSB2,
+       .fops       = &vdev_fops,
+};
+
+
+static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
+                              struct pvr2_v4l2 *vp,
+                              enum pvr2_config cfg)
+{
+       int mindevnum;
+       int unit_number;
+       int v4l_type;
+       dip->v4lp = vp;
+       dip->config = cfg;
+
+
+       switch (cfg) {
+       case pvr2_config_mpeg:
+               v4l_type = VFL_TYPE_GRABBER;
+               dip->stream = &vp->channel.mc_head->video_stream;
+               break;
+       case pvr2_config_vbi:
+               v4l_type = VFL_TYPE_VBI;
+               break;
+       case pvr2_config_radio:
+               v4l_type = VFL_TYPE_RADIO;
+               break;
+       default:
+               /* Bail out (this should be impossible) */
+               err("Failed to set up pvrusb2 v4l dev"
+                   " due to unrecognized config");
+               return;
+       }
+
+       if (!dip->stream) {
+               err("Failed to set up pvrusb2 v4l dev"
+                   " due to missing stream instance");
+               return;
+       }
+
+       dip->vdev = video_device_alloc();
+       if (!dip->vdev) {
+               err("Alloc of pvrusb2 v4l video device failed");
+               return;
+       }
+
+       memcpy(dip->vdev,&vdev_template,sizeof(vdev_template));
+       dip->vdev->release = video_device_release;
+       mutex_lock(&device_lock);
+
+       mindevnum = -1;
+       unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
+       if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+               mindevnum = video_nr[unit_number];
+       }
+       if ((video_register_device(dip->vdev, v4l_type, mindevnum) < 0) &&
+           (video_register_device(dip->vdev, v4l_type, -1) < 0)) {
+               err("Failed to register pvrusb2 v4l video device");
+       } else {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "registered device video%d [%s]",
+                          dip->vdev->minor,pvr2_config_get_name(dip->config));
+       }
+
+       if ((dip->vdev->minor < sizeof(devices)/sizeof(devices[0])) &&
+           (devices[dip->vdev->minor] == NULL)) {
+               dip->ctxt_idx = dip->vdev->minor;
+               devices[dip->ctxt_idx] = dip;
+       }
+       mutex_unlock(&device_lock);
+
+       pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
+                                       dip->vdev->minor);
+}
+
+
+struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
+{
+       struct pvr2_v4l2 *vp;
+
+       vp = kmalloc(sizeof(*vp),GFP_KERNEL);
+       if (!vp) return vp;
+       memset(vp,0,sizeof(*vp));
+       vp->video_dev.ctxt_idx = -1;
+       pvr2_channel_init(&vp->channel,mnp);
+       pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
+
+       vp->channel.check_func = pvr2_v4l2_internal_check;
+
+       /* register streams */
+       pvr2_v4l2_dev_init(&vp->video_dev,vp,pvr2_config_mpeg);
+
+
+       return vp;
+}
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
new file mode 100644 (file)
index 0000000..9a995e2
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 __PVRUSB2_V4L2_H
+#define __PVRUSB2_V4L2_H
+
+#include "pvrusb2-context.h"
+
+struct pvr2_v4l2;
+
+struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *);
+
+#endif /* __PVRUSB2_V4L2_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
new file mode 100644 (file)
index 0000000..e4ec7f2
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+
+   This source file is specifically designed to interface with the
+   saa711x support that is available in the v4l available starting
+   with linux 2.6.15.
+
+*/
+
+#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/saa7115.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_decoder {
+       struct pvr2_i2c_handler handler;
+       struct pvr2_decoder_ctrl ctrl;
+       struct pvr2_i2c_client *client;
+       struct pvr2_hdw *hdw;
+       unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_decoder *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       struct v4l2_routing route;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
+       switch(hdw->input_val) {
+       case PVR2_CVAL_INPUT_TV:
+               route.input = SAA7115_COMPOSITE4;
+               break;
+       case PVR2_CVAL_INPUT_COMPOSITE:
+               route.input = SAA7115_COMPOSITE5;
+               break;
+       case PVR2_CVAL_INPUT_SVIDEO:
+               route.input = SAA7115_SVIDEO2;
+               break;
+       case PVR2_CVAL_INPUT_RADIO:
+               // ????? No idea yet what to do here
+       default:
+               return;
+       }
+       route.output = 0;
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
+}
+
+
+static int check_input(struct pvr2_v4l_decoder *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return hdw->input_dirty != 0;
+}
+
+
+static void set_audio(struct pvr2_v4l_decoder *ctxt)
+{
+       u32 val;
+       struct pvr2_hdw *hdw = ctxt->hdw;
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_audio %d",
+                  hdw->srate_val);
+       switch (hdw->srate_val) {
+       default:
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+               val = 48000;
+               break;
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+               val = 44100;
+               break;
+       case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+               val = 32000;
+               break;
+       }
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
+}
+
+
+static int check_audio(struct pvr2_v4l_decoder *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return hdw->srate_dirty != 0;
+}
+
+
+struct pvr2_v4l_decoder_ops {
+       void (*update)(struct pvr2_v4l_decoder *);
+       int (*check)(struct pvr2_v4l_decoder *);
+};
+
+
+static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
+       { .update = set_input, .check = check_input},
+       { .update = set_audio, .check = check_audio},
+};
+
+
+static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
+{
+       ctxt->client->handler = 0;
+       ctxt->hdw->decoder_ctrl = 0;
+       kfree(ctxt);
+}
+
+
+static int decoder_check(struct pvr2_v4l_decoder *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (ctxt->stale_mask & msk) continue;
+               if (decoder_ops[idx].check(ctxt)) {
+                       ctxt->stale_mask |= msk;
+               }
+       }
+       return ctxt->stale_mask != 0;
+}
+
+
+static void decoder_update(struct pvr2_v4l_decoder *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (!(ctxt->stale_mask & msk)) continue;
+               ctxt->stale_mask &= ~msk;
+               decoder_ops[idx].update(ctxt);
+       }
+}
+
+
+static int decoder_detect(struct pvr2_i2c_client *cp)
+{
+       /* Attempt to query the decoder - let's see if it will answer */
+       struct v4l2_tuner vt;
+       int ret;
+
+       memset(&vt,0,sizeof(vt));
+       ret = pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&vt);
+       return ret == 0; /* Return true if it answered */
+}
+
+
+static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
+{
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 decoder_enable(%d)",fl);
+       pvr2_v4l2_cmd_stream(ctxt->client,fl);
+}
+
+
+static int decoder_is_tuned(struct pvr2_v4l_decoder *ctxt)
+{
+       struct v4l2_tuner vt;
+       int ret;
+
+       memset(&vt,0,sizeof(vt));
+       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
+       if (ret < 0) return -EINVAL;
+       return vt.signal ? 1 : 0;
+}
+
+
+static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+       .detach = (void (*)(void *))decoder_detach,
+       .check = (int (*)(void *))decoder_check,
+       .update = (void (*)(void *))decoder_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
+};
+
+
+int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
+                              struct pvr2_i2c_client *cp)
+{
+       struct pvr2_v4l_decoder *ctxt;
+
+       if (hdw->decoder_ctrl) return 0;
+       if (cp->handler) return 0;
+       if (!decoder_detect(cp)) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->handler.func_data = ctxt;
+       ctxt->handler.func_table = &hfuncs;
+       ctxt->ctrl.ctxt = ctxt;
+       ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
+       ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
+       ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
+                                 sizeof(decoder_ops[0]))) - 1;
+       hdw->decoder_ctrl = &ctxt->ctrl;
+       cp->handler = &ctxt->handler;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
new file mode 100644 (file)
index 0000000..2b917fd
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_VIDEO_V4L_H
+#define __PVRUSB2_VIDEO_V4L_H
+
+/*
+
+   This module connects the pvrusb2 driver to the I2C chip level
+   driver which handles device video processing.  This interface is
+   used internally by the driver; higher level code should only
+   interact through the interface provided by pvrusb2-hdw.h.
+
+*/
+
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_VIDEO_V4L_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
new file mode 100644 (file)
index 0000000..fcad346
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+
+   This source file is specifically designed to interface with the
+   wm8775.
+
+*/
+
+#include "pvrusb2-wm8775.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_wm8775 {
+       struct pvr2_i2c_handler handler;
+       struct pvr2_i2c_client *client;
+       struct pvr2_hdw *hdw;
+       unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_wm8775 *ctxt)
+{
+       struct v4l2_routing route;
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       int msk = 0;
+
+       memset(&route,0,sizeof(route));
+
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d msk=0x%x)",
+                  hdw->input_val,msk);
+
+       // Always point to input #1 no matter what
+       route.input = 2;
+       pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+static int check_input(struct pvr2_v4l_wm8775 *ctxt)
+{
+       struct pvr2_hdw *hdw = ctxt->hdw;
+       return hdw->input_dirty != 0;
+}
+
+
+struct pvr2_v4l_wm8775_ops {
+       void (*update)(struct pvr2_v4l_wm8775 *);
+       int (*check)(struct pvr2_v4l_wm8775 *);
+};
+
+
+static const struct pvr2_v4l_wm8775_ops wm8775_ops[] = {
+       { .update = set_input, .check = check_input},
+};
+
+
+static unsigned int wm8775_describe(struct pvr2_v4l_wm8775 *ctxt,
+                                    char *buf,unsigned int cnt)
+{
+       return scnprintf(buf,cnt,"handler: pvrusb2-wm8775");
+}
+
+
+static void wm8775_detach(struct pvr2_v4l_wm8775 *ctxt)
+{
+       ctxt->client->handler = 0;
+       kfree(ctxt);
+}
+
+
+static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (ctxt->stale_mask & msk) continue;
+               if (wm8775_ops[idx].check(ctxt)) {
+                       ctxt->stale_mask |= msk;
+               }
+       }
+       return ctxt->stale_mask != 0;
+}
+
+
+static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
+{
+       unsigned long msk;
+       unsigned int idx;
+
+       for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
+            idx++) {
+               msk = 1 << idx;
+               if (!(ctxt->stale_mask & msk)) continue;
+               ctxt->stale_mask &= ~msk;
+               wm8775_ops[idx].update(ctxt);
+       }
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+       .detach = (void (*)(void *))wm8775_detach,
+       .check = (int (*)(void *))wm8775_check,
+       .update = (void (*)(void *))wm8775_update,
+       .describe = (unsigned int (*)(void *,char *,unsigned int))wm8775_describe,
+};
+
+
+int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+       struct pvr2_v4l_wm8775 *ctxt;
+
+       if (cp->handler) return 0;
+
+       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       if (!ctxt) return 0;
+       memset(ctxt,0,sizeof(*ctxt));
+
+       ctxt->handler.func_data = ctxt;
+       ctxt->handler.func_table = &hfuncs;
+       ctxt->client = cp;
+       ctxt->hdw = hdw;
+       ctxt->stale_mask = (1 << (sizeof(wm8775_ops)/
+                                 sizeof(wm8775_ops[0]))) - 1;
+       cp->handler = &ctxt->handler;
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
+                  cp->client->addr);
+       return !0;
+}
+
+
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
new file mode 100644 (file)
index 0000000..8aaeff4
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_WM8775_H
+#define __PVRUSB2_WM8775_H
+
+/*
+
+   This module connects the pvrusb2 driver to the I2C chip level
+   driver which performs analog -> digital audio conversion for
+   external audio inputs.  This interface is used internally by the
+   driver; higher level code should only interact through the
+   interface provided by pvrusb2-hdw.h.
+
+*/
+
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_WM8775_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2.h b/drivers/media/video/pvrusb2/pvrusb2.h
new file mode 100644 (file)
index 0000000..074533e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PVRUSB2_H
+#define __PVRUSB2_H
+
+/* Maximum number of pvrusb2 instances we can track at once.  You
+   might want to increase this - however the driver operation will not
+   be impaired if it is too small.  Instead additional units just
+   won't have an ID assigned and it might not be possible to specify
+   module paramters for those extra units. */
+#define PVR_NUM 20
+
+#endif /* __PVRUSB2_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 70 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
index de7b9e6e932a9b70aec1e53e2ff5d3ff985369c9..afc8f352b8e713ea66c9a15a50f0fcb05f24ba31 100644 (file)
@@ -432,10 +432,10 @@ static void saa6752hs_old_set_params(struct i2c_client* client,
 }
 
 static int handle_ctrl(struct saa6752hs_mpeg_params *params,
-               struct v4l2_ext_control *ctrl, int cmd)
+               struct v4l2_ext_control *ctrl, unsigned int cmd)
 {
        int old = 0, new;
-       int set = cmd == VIDIOC_S_EXT_CTRLS;
+       int set = (cmd == VIDIOC_S_EXT_CTRLS);
 
        new = ctrl->value;
        switch (ctrl->id) {
index f0c2111f14ad1f11c5bbe0575edd6aedd23420bd..da3007d2f4115df49b6a53ba01dec178a7292529 100644 (file)
@@ -871,9 +871,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
        printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
-              "latency: %d, mmio: 0x%lx\n", dev->name,
+              "latency: %d, mmio: 0x%llx\n", dev->name,
               pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
-              dev->pci_lat,pci_resource_start(pci_dev,0));
+              dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
        pci_set_master(pci_dev);
        if (!pci_dma_supported(pci_dev, DMA_32BIT_MASK)) {
                printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name);
@@ -905,8 +905,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
                                pci_resource_len(pci_dev,0),
                                dev->name)) {
                err = -EBUSY;
-               printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
-                      dev->name,pci_resource_start(pci_dev,0));
+               printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+                      dev->name,(unsigned long long)pci_resource_start(pci_dev,0));
                goto fail1;
        }
        dev->lmmio = ioremap(pci_resource_start(pci_dev,0), 0x1000);
index 6be9c1131e1fc19898c74e9406e932b0e252a3f3..c18b31d9928c8d59f1e60906db240352dc105a65 100644 (file)
@@ -2190,7 +2190,7 @@ static struct pci_driver stradis_driver = {
        .remove = __devexit_p(stradis_remove)
 };
 
-int __init stradis_init(void)
+static int __init stradis_init(void)
 {
        int retval;
 
@@ -2203,7 +2203,7 @@ int __init stradis_init(void)
        return retval;
 }
 
-void __exit stradis_exit(void)
+static void __exit stradis_exit(void)
 {
        pci_unregister_driver(&stradis_driver);
        printk(KERN_INFO "stradis: module cleanup complete\n");
index b6ae969563b2ba9e3d6cefde6e51bcd21b7cbc43..2fadabf99688c766dc3aa170b4b0ead3afdea435 100644 (file)
 */
 
 #define tda9887_info(fmt, arg...) do {\
-       printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+       printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
                        i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 #define tda9887_dbg(fmt, arg...) do {\
        if (tuner_debug) \
-               printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+               printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
                        i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 
 
@@ -84,8 +84,7 @@ struct tvnorm {
 #define cAudioGain6             0x80    // bit c7
 
 #define cTopMask                0x1f    // bit c0:4
-#define cTopPalSecamDefault    0x14    // bit c0:4
-#define cTopNtscRadioDefault   0x10    // bit c0:4
+#define cTopDefault            0x10    // bit c0:4
 
 //// third reg (e)
 #define cAudioIF_4_5             0x00    // bit e0:1
@@ -123,7 +122,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis50  |
-                          cTopPalSecamDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_5_5   |
                           cVideoIF_38_90 ),
@@ -134,7 +133,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis50  |
-                          cTopPalSecamDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_0   |
                           cVideoIF_38_90 ),
@@ -145,7 +144,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis50  |
-                          cTopPalSecamDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_5   |
                           cVideoIF_38_90 ),
@@ -156,7 +155,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis75  |
-                          cTopNtscRadioDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_4_5   |
                           cVideoIF_45_75 ),
@@ -165,7 +164,7 @@ static struct tvnorm tvnorms[] = {
                .name  = "SECAM-BGH",
                .b     = ( cPositiveAmTV  |
                           cQSS           ),
-               .c     = ( cTopPalSecamDefault),
+               .c     = ( cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_5_5   |
                           cVideoIF_38_90 ),
@@ -174,7 +173,7 @@ static struct tvnorm tvnorms[] = {
                .name  = "SECAM-L",
                .b     = ( cPositiveAmTV  |
                           cQSS           ),
-               .c     = ( cTopPalSecamDefault),
+               .c     = ( cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_5   |
                           cVideoIF_38_90 ),
@@ -184,7 +183,7 @@ static struct tvnorm tvnorms[] = {
                .b     = ( cOutputPort2Inactive |
                           cPositiveAmTV  |
                           cQSS           ),
-               .c     = ( cTopPalSecamDefault),
+               .c     = ( cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_5   |
                           cVideoIF_33_90 ),
@@ -195,7 +194,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis50  |
-                          cTopPalSecamDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_6_5   |
                           cVideoIF_38_90 ),
@@ -206,7 +205,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis75  |
-                          cTopNtscRadioDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_4_5   |
                           cVideoIF_45_75 ),
@@ -217,7 +216,7 @@ static struct tvnorm tvnorms[] = {
                           cQSS           ),
                .c     = ( cDeemphasisON  |
                           cDeemphasis50  |
-                          cTopNtscRadioDefault),
+                          cTopDefault),
                .e     = ( cGating_36     |
                           cAudioIF_4_5   |
                           cVideoIF_58_75 ),
@@ -230,7 +229,7 @@ static struct tvnorm radio_stereo = {
                  cQSS           ),
        .c    = ( cDeemphasisOFF |
                  cAudioGain6    |
-                 cTopNtscRadioDefault),
+                 cTopDefault),
        .e    = ( cTunerGainLow  |
                  cAudioIF_5_5   |
                  cRadioIF_38_90 ),
@@ -242,7 +241,7 @@ static struct tvnorm radio_mono = {
                  cQSS           ),
        .c    = ( cDeemphasisON  |
                  cDeemphasis75  |
-                 cTopNtscRadioDefault),
+                 cTopDefault),
        .e    = ( cTunerGainLow  |
                  cAudioIF_5_5   |
                  cRadioIF_38_90 ),
index a26ded7d6faef86d7ff23ee4b44b9786e099b784..011413cf34a8ad9fcdec570d636d2819edde0c77 100644 (file)
@@ -40,7 +40,6 @@ static unsigned int no_autodetect = 0;
 static unsigned int show_i2c = 0;
 
 /* insmod options used at runtime => read/write */
-static unsigned int tuner_debug_old = 0;
 int tuner_debug = 0;
 
 static unsigned int tv_range[2] = { 44, 958 };
@@ -54,8 +53,6 @@ static char ntsc[] = "-";
 module_param(addr, int, 0444);
 module_param(no_autodetect, int, 0444);
 module_param(show_i2c, int, 0444);
-/* Note: tuner_debug is deprecated and will be removed in 2.6.17 */
-module_param_named(tuner_debug,tuner_debug_old, int, 0444);
 module_param_named(debug,tuner_debug, int, 0644);
 module_param_string(pal, pal, sizeof(pal), 0644);
 module_param_string(secam, secam, sizeof(secam), 0644);
@@ -442,11 +439,6 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        t->audmode = V4L2_TUNER_MODE_STEREO;
        t->mode_mask = T_UNINITIALIZED;
        t->tuner_status = tuner_status;
-       if (tuner_debug_old) {
-               tuner_debug = tuner_debug_old;
-               printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n");
-               printk(KERN_ERR "tuner: use the debug option instead.\n");
-       }
 
        if (show_i2c) {
                unsigned char buffer[16];
index f4b3d64ebf73ff7ff11958a8b2ac8cab6655d0b1..97f946db85978ae23e816b82b17d7ac84aa67e18 100644 (file)
@@ -1103,7 +1103,7 @@ const char **v4l2_ctrl_get_menu(u32 id)
        };
        static const char *mpeg_stream_vbi_fmt[] = {
                "No VBI",
-               "VBI in private packets, IVTV format",
+               "Private packet, IVTV format",
                NULL
        };
 
index 2dfa7f23d0ca28f7e08a2fa7167184789c32cc29..b26ebaff226f49182537c0a350ff4189969eaddf 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
@@ -1563,10 +1562,6 @@ int video_register_device(struct video_device *vfd, int type, int nr)
        video_device[i]=vfd;
        vfd->minor=i;
        mutex_unlock(&videodev_lock);
-
-       sprintf(vfd->devfs_name, "v4l/%s%d", name_base, i - base);
-       devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor),
-                       S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name);
        mutex_init(&vfd->lock);
 
        /* sysfs class */
@@ -1575,7 +1570,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
                vfd->class_dev.dev = vfd->dev;
        vfd->class_dev.class       = &video_class;
        vfd->class_dev.devt        = MKDEV(VIDEO_MAJOR, vfd->minor);
-       strlcpy(vfd->class_dev.class_id, vfd->devfs_name + 4, BUS_ID_SIZE);
+       sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base);
        class_device_register(&vfd->class_dev);
        class_device_create_file(&vfd->class_dev,
                                &class_device_attr_name);
@@ -1604,7 +1599,6 @@ void video_unregister_device(struct video_device *vfd)
        if(video_device[vfd->minor]!=vfd)
                panic("videodev: bad unregister");
 
-       devfs_remove(vfd->devfs_name);
        video_device[vfd->minor]=NULL;
        class_device_unregister(&vfd->class_dev);
        mutex_unlock(&videodev_lock);
index 74714e5bcf03299cc960529ab25c66ef3a061d0b..3ff8378ea660ad9aad1330122efd408f5faade01 100644 (file)
@@ -305,10 +305,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
        }
 
  out:
-       if (pp0_array)
-               kfree(pp0_array);
-       if (p0_array)
-               kfree(p0_array);
+       kfree(pp0_array);
+       kfree(p0_array);
        return rc;
 }
 
index af6ec553ff7ca54c3cf4ee14c7e43e32cd9e73a2..85689ab46cbc26fcc30db0e471cc5081abd5dc66 100644 (file)
@@ -1378,8 +1378,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
        return 0;
 
  out_free_port_info:
-       if (hba)
-               kfree(hba);
+       kfree(hba);
  out:
        return error;
 }
index 7d4c5497785b3c1dd1d1709733b5a899e5547c6a..1ddc2fb429d5668a2f653c2c3e5d7561e5a4a92d 100644 (file)
@@ -1089,7 +1089,6 @@ static int i2o_block_probe(struct device *dev)
        gd = i2o_blk_dev->gd;
        gd->first_minor = unit << 4;
        sprintf(gd->disk_name, "i2o/hd%c", 'a' + unit);
-       sprintf(gd->devfs_name, "i2o/hd%c", 'a' + unit);
        gd->driverfs_dev = &i2o_dev->device;
 
        /* setup request queue */
index febbdd4e0605ddeed250f534ebeda84ac77682ac..3305c12372a2f341c68fbca98f3ab5c58e2f7f9a 100644 (file)
@@ -683,9 +683,10 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
                        c->mem_alloc = 1;
                        sb->current_mem_size = 1 + res->end - res->start;
                        sb->current_mem_base = res->start;
-                       osm_info("%s: allocated %ld bytes of PCI memory at "
-                                "0x%08lX.\n", c->name,
-                                1 + res->end - res->start, res->start);
+                       osm_info("%s: allocated %llu bytes of PCI memory at "
+                               "0x%016llX.\n", c->name,
+                               (unsigned long long)(1 + res->end - res->start),
+                               (unsigned long long)res->start);
                }
        }
 
@@ -704,9 +705,10 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
                        c->io_alloc = 1;
                        sb->current_io_size = 1 + res->end - res->start;
                        sb->current_mem_base = res->start;
-                       osm_info("%s: allocated %ld bytes of PCI I/O at 0x%08lX"
-                                ".\n", c->name, 1 + res->end - res->start,
-                                res->start);
+                       osm_info("%s: allocated %llu bytes of PCI I/O at "
+                               "0x%016llX.\n", c->name,
+                               (unsigned long long)(1 + res->end - res->start),
+                               (unsigned long long)res->start);
                }
        }
 
@@ -1239,7 +1241,6 @@ EXPORT_SYMBOL(i2o_cntxt_list_remove);
 EXPORT_SYMBOL(i2o_cntxt_list_get_ptr);
 #endif
 EXPORT_SYMBOL(i2o_msg_get_wait);
-EXPORT_SYMBOL(i2o_msg_nop);
 EXPORT_SYMBOL(i2o_find_iop);
 EXPORT_SYMBOL(i2o_iop_find_device);
 EXPORT_SYMBOL(i2o_event_register);
index 1fdf03fd2da751181c1226d6441de7dab786b6e2..9706cc19134a1bc7b96e812e2717846ded951717 100644 (file)
@@ -85,7 +85,7 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi
        }
        memset(sp, 0, sizeof(struct service_processor));
 
-       sp->lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&sp->lock);
        INIT_LIST_HEAD(&sp->command_queue);
 
        pci_set_drvdata(pdev, (void *)sp);
index 587458b370b9a9d71c817d0375d140847f01c505..115cc21094b941a243d323756f127f905b14e0bf 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/hdreg.h>
 #include <linux/kdev_t.h>
 #include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/mutex.h>
 
 #include <linux/mmc/card.h>
@@ -409,7 +408,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
         */
 
        sprintf(md->disk->disk_name, "mmcblk%d", devidx);
-       sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
 
        blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
 
@@ -555,7 +553,6 @@ static int __init mmc_blk_init(void)
        if (major == 0)
                major = res;
 
-       devfs_mk_dir("mmc");
        return mmc_register_driver(&mmc_driver);
 
  out:
@@ -565,7 +562,6 @@ static int __init mmc_blk_init(void)
 static void __exit mmc_blk_exit(void)
 {
        mmc_unregister_driver(&mmc_driver);
-       devfs_remove("mmc");
        unregister_blkdev(major, "mmc");
 }
 
index da8e4d7339cc42f6d2cc7c58106e6bf9604ffe40..8576a65ca1c3383fbdf2c74ff895fbc8b75e7ba7 100644 (file)
@@ -546,9 +546,9 @@ static int mmci_probe(struct amba_device *dev, void *id)
 
        mmc_add_host(mmc);
 
-       printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n",
+       printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
                mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
-               dev->res.start, dev->irq[0], dev->irq[1]);
+               (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
 
        init_timer(&host->timer);
        host->timer.data = (unsigned long)host;
index 0d435814aaa137aba3274696c0a118515f155fa4..39edb8250fbc13f85f23347f6aff7b9a0c20d6a4 100644 (file)
@@ -357,6 +357,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
        mtd->resume  = cfi_intelext_resume;
        mtd->flags   = MTD_CAP_NORFLASH;
        mtd->name    = map->name;
+       mtd->writesize = 1;
 
        mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
 
index c40b48dabed362c00a5bc2c001a75d2131a6b05c..2c3f019197c116463b74b04645dd6baf54e0dd65 100644 (file)
@@ -256,6 +256,7 @@ static struct mtd_info *jedec_probe(struct map_info *map)
    MTD->name = map->name;
    MTD->type = MTD_NORFLASH;
    MTD->flags = MTD_CAP_NORFLASH;
+   MTD->writesize = 1;
    MTD->erasesize = SectorSize*(map->buswidth);
    //   printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
    MTD->size = priv->size;
index a611de9b15159349116d78d28fdb2968b29f2c62..ac01a949b687a4513e7217c0c59ac1f492d06a45 100644 (file)
@@ -64,7 +64,8 @@ static struct mtd_info *map_absent_probe(struct map_info *map)
        mtd->write      = map_absent_write;
        mtd->sync       = map_absent_sync;
        mtd->flags      = 0;
-       mtd->erasesize = PAGE_SIZE;
+       mtd->erasesize  = PAGE_SIZE;
+       mtd->writesize  = 1;
 
        __module_get(THIS_MODULE);
        return mtd;
index 763925747db6f60a6701aad1b68e2fdecb801457..3a66680abfd06cc3b3c6b60e129e957d84e912a9 100644 (file)
@@ -71,6 +71,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
        mtd->write = mapram_write;
        mtd->sync = mapram_nop;
        mtd->flags = MTD_CAP_RAM;
+       mtd->writesize = 1;
 
        mtd->erasesize = PAGE_SIZE;
        while(mtd->size & (mtd->erasesize - 1))
index bc6ee9ef8a31ac8d6a44ef054d9d0a33d9dc9a23..1b328b1378fda2d9d288d535434a7113a7262d74 100644 (file)
@@ -47,6 +47,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
        mtd->sync = maprom_nop;
        mtd->flags = MTD_CAP_ROM;
        mtd->erasesize = map->size;
+       mtd->writesize = 1;
 
        __module_get(THIS_MODULE);
        return mtd;
index 0d98c223c5fc2e188d1f1e58ad0ea53ca0d1a506..be3f1c136d0211340a5b890b0f5648dd07c10777 100644 (file)
@@ -324,6 +324,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
 
        dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
        dev->mtd.erasesize = erase_size;
+       dev->mtd.writesize = 1;
        dev->mtd.type = MTD_RAM;
        dev->mtd.flags = MTD_CAP_RAM;
        dev->mtd.erase = block2mtd_erase;
index 4ab7670770e43ff1cc9a0d855b872e1c22656f1e..08dfb899b27204ef036e693826643bd6452d8f38 100644 (file)
@@ -225,6 +225,7 @@ static int __init ms02nv_init_one(ulong addr)
        mtd->owner = THIS_MODULE;
        mtd->read = ms02nv_read;
        mtd->write = ms02nv_write;
+       mtd->writesize = 1;
 
        ret = -EIO;
        if (add_mtd_device(mtd)) {
index a19480d07888dfd043872b2e5d715755851a17e8..04271d02b6b6d990c1c32d363bea309792dbde4a 100644 (file)
@@ -478,6 +478,7 @@ add_dataflash(struct spi_device *spi, char *name,
        device->name = (pdata && pdata->name) ? pdata->name : priv->name;
        device->size = nr_pages * pagesize;
        device->erasesize = pagesize;
+       device->writesize = pagesize;
        device->owner = THIS_MODULE;
        device->type = MTD_DATAFLASH;
        device->flags = MTD_CAP_NORFLASH;
index e09e416667d38daea36e24b8034daa86597adb79..6c7337f9ebbbfce6edc1f204f1d1b58d6bff2be5 100644 (file)
@@ -151,6 +151,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
        new->mtd.owner = THIS_MODULE;
        new->mtd.type = MTD_RAM;
        new->mtd.erasesize = PAGE_SIZE;
+       new->mtd.writesize = 1;
 
        ret = -EAGAIN;
        if (add_mtd_device(&new->mtd)) {
index 666cce1bf60c0dddea6df065f47c89cd22330ef9..30f07b473ae2ad55b026c4f2ea23d30520c03957 100644 (file)
@@ -551,11 +551,11 @@ static u32 fixup_pmc551 (struct pci_dev *dev)
         /*
          * Some screen fun
          */
-        printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%lx\n",
+        printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%llx\n",
               (size<1024)?size:(size<1048576)?size>>10:size>>20,
                (size<1024)?'B':(size<1048576)?'K':'M',
               size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
-               (dev->resource[0].start)&PCI_BASE_ADDRESS_MEM_MASK );
+               (unsigned long long)((dev->resource[0].start)&PCI_BASE_ADDRESS_MEM_MASK));
 
         /*
          * Check to see the state of the memory
@@ -685,8 +685,8 @@ static int __init init_pmc551(void)
                         break;
                 }
 
-                printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%lX\n",
-                                   PCI_Device->resource[0].start);
+                printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%llx\n",
+                                   (unsigned long long)PCI_Device->resource[0].start);
 
                 /*
                  * The PMC551 device acts VERY weird if you don't init it
@@ -778,7 +778,8 @@ static int __init init_pmc551(void)
                 mtd->type      = MTD_RAM;
                 mtd->name      = "PMC551 RAM board";
                 mtd->erasesize         = 0x10000;
-               mtd->owner = THIS_MODULE;
+                mtd->writesize  = 1;
+                mtd->owner = THIS_MODULE;
 
                 if (add_mtd_device(mtd)) {
                         printk(KERN_NOTICE "pmc551: Failed to register new device\n");
index b3f665e3c38bfeec5fade51e3c4fb77ee61bc7b4..542a0c009006d4b682d30c03fa437a4f0b62a2aa 100644 (file)
@@ -209,6 +209,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
        (*curmtd)->mtdinfo->owner = THIS_MODULE;
        (*curmtd)->mtdinfo->type = MTD_RAM;
        (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
+       (*curmtd)->mtdinfo->writesize = 1;
 
        if (add_mtd_device((*curmtd)->mtdinfo)) {
                E("slram: Failed to register new device\n");
index c350878d4592978ffece3fe1b1e97cb4caae5187..a505870052635b6acc253b42c565e41099cc7ec6 100644 (file)
@@ -123,9 +123,10 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
                window->rsrc.parent = NULL;
                printk(KERN_ERR MOD_NAME
                        " %s(): Unable to register resource"
-                       " 0x%.08lx-0x%.08lx - kernel bug?\n",
+                       " 0x%.16llx-0x%.16llx - kernel bug?\n",
                        __func__,
-                       window->rsrc.start, window->rsrc.end);
+                       (unsigned long long)window->rsrc.start,
+                       (unsigned long long)window->rsrc.end);
        }
 
 #if 0
index ea5073781b3a38265053e2710606d5ef26464854..16732794edf31b8ebb522528f3bb330a97f7ea22 100644 (file)
@@ -177,9 +177,10 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
                window->rsrc.parent = NULL;
                printk(KERN_DEBUG MOD_NAME
                        ": %s(): Unable to register resource"
-                       " 0x%.08lx-0x%.08lx - kernel bug?\n",
+                       " 0x%.16llx-0x%.16llx - kernel bug?\n",
                        __func__,
-                       window->rsrc.start, window->rsrc.end);
+                       (unsigned long long)window->rsrc.start,
+                       (unsigned long long)window->rsrc.end);
        }
 
        /* Map the firmware hub into my address space. */
index 2c9cc7f37e9216fcf5cae2d8e526514114e178b1..c26488a1793abd769ede3be3083afb5562c98925 100644 (file)
@@ -42,7 +42,6 @@ struct ixp2000_flash_info {
        struct          map_info map;
        struct          mtd_partition *partitions;
        struct          resource *res;
-       int             nr_banks;
 };
 
 static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
@@ -183,7 +182,6 @@ static int ixp2000_flash_probe(struct platform_device *dev)
         */
        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;
 
index 433c3cac3ca959285e0cd87e33829e2540c53acc..d6301f08906dffd0b769643a55a3281b13f2dcb6 100644 (file)
@@ -182,7 +182,7 @@ static struct physmap_flash_data physmap_flash_data = {
 
 static struct resource physmap_flash_resource = {
        .start          = CONFIG_MTD_PHYSMAP_START,
-       .end            = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN,
+       .end            = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
        .flags          = IORESOURCE_MEM,
 };
 
index 28b8a571a91a4ff60f133b5de4ed127684d5d78c..331a15859d710df20354f143e5f34a98ae17e22e 100644 (file)
@@ -164,8 +164,9 @@ static int __init init_scx200_docflash(void)
                outl(pmr, scx200_cb_base + SCx200_PMR);
        }
 
-               printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n",
-              docmem.start, docmem.end, width);
+               printk(KERN_INFO NAME ": DOCCS mapped at 0x%llx-0x%llx, width %d\n",
+                       (unsigned long long)docmem.start,
+                       (unsigned long long)docmem.end, width);
 
        scx200_docflash_map.size = size;
        if (width == 8)
index 24a03152d196fc494cc0605827fbd66347699401..4db2055cee31ef9e68967e9d56a3e4c7d4b731c6 100644 (file)
@@ -62,9 +62,10 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
                /* Non-CFI userflash device-- once I find one we
                 * can work on supporting it.
                 */
-               printk("%s: unsupported device at 0x%lx (%d regs): " \
+               printk("%s: unsupported device at 0x%llx (%d regs): " \
                        "email ebrower@usa.net\n",
-                      dp->full_name, res->start, edev->num_addrs);
+                      dp->full_name, (unsigned long long)res->start,
+                      edev->num_addrs);
 
                return -ENODEV;
        }
index aa18d45b264bb2d3aef9c71792401ac1d7ccece5..9a4b59d925252a554c4840455b6e00455e6aa7df 100644 (file)
@@ -78,7 +78,7 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
                return -EINVAL;
        }
 
-       if (offset >= 0 && offset < mtd->size)
+       if (offset >= 0 && offset <= mtd->size)
                return file->f_pos = offset;
 
        return -EINVAL;
index 27083ed0a017a6af2da8d41ad48d466e7b98a86d..80a76654d963749a18d2c9a79a5df29f1093159c 100644 (file)
@@ -1176,7 +1176,7 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
 
        status = chip->waitfunc(mtd, chip);
 
-       return status;
+       return status & NAND_STATUS_FAIL ? -EIO : 0;
 }
 
 /**
@@ -1271,10 +1271,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
                buf = nand_transfer_oob(chip, buf, ops);
 
-               readlen -= ops->ooblen;
-               if (!readlen)
-                       break;
-
                if (!(chip->options & NAND_NO_READRDY)) {
                        /*
                         * Apply delay or wait for ready/busy pin. Do this
@@ -1288,6 +1284,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                                nand_wait_ready(mtd);
                }
 
+               readlen -= ops->ooblen;
+               if (!readlen)
+                       break;
+
                /* Increment page address */
                realpage++;
 
@@ -1610,13 +1610,13 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        if (!writelen)
                return 0;
 
+       chipnr = (int)(to >> chip->chip_shift);
+       chip->select_chip(mtd, chipnr);
+
        /* Check, if it is write protected */
        if (nand_check_wp(mtd))
                return -EIO;
 
-       chipnr = (int)(to >> chip->chip_shift);
-       chip->select_chip(mtd, chipnr);
-
        realpage = (int)(to >> chip->page_shift);
        page = realpage & chip->pagemask;
        blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
index fe8d38514ba655ce79e8b4bc788726a5e6e060d5..e5bd88f2d560ae3966fe5169c6885c5c0d4d235f 100644 (file)
@@ -61,15 +61,15 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
 
 static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd->priv;
+       struct ndfc_controller *ndfc = &ndfc_ctrl;
 
        if (cmd == NAND_CMD_NONE)
                return;
 
        if (ctrl & NAND_CLE)
-               writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD);
+               writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD);
        else
-               writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE);
+               writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
 }
 
 static int ndfc_ready(struct mtd_info *mtd)
index 2c262fe03d8af60a93bd6cda681246bf4b7d9ce6..ff5cef24d5bb3ccbfc9ce0476e6db222c43af160 100644 (file)
@@ -63,8 +63,6 @@
 #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
@@ -99,6 +97,12 @@ struct s3c2410_nand_mtd {
        int                             scan_res;
 };
 
+enum s3c_cpu_type {
+       TYPE_S3C2410,
+       TYPE_S3C2412,
+       TYPE_S3C2440,
+};
+
 /* overview of the s3c2410 nand state */
 
 struct s3c2410_nand_info {
@@ -112,9 +116,11 @@ struct s3c2410_nand_info {
        struct resource                 *area;
        struct clk                      *clk;
        void __iomem                    *regs;
+       void __iomem                    *sel_reg;
+       int                             sel_bit;
        int                             mtd_count;
 
-       unsigned char                   is_s3c2440;
+       enum s3c_cpu_type               cpu_type;
 };
 
 /* conversion functions */
@@ -148,7 +154,7 @@ static inline int allow_clk_stop(struct s3c2410_nand_info *info)
 
 #define NS_IN_KHZ 1000000
 
-static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
+static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
 {
        int result;
 
@@ -172,53 +178,58 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
 
 /* controller setup */
 
-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_device *pdev)
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
+                              struct platform_device *pdev)
 {
        struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
        unsigned long clkrate = clk_get_rate(info->clk);
+       int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
        int tacls, twrph0, twrph1;
-       unsigned long cfg;
+       unsigned long cfg = 0;
 
        /* calculate the timing information for the controller */
 
        clkrate /= 1000;        /* turn clock into kHz for ease of use */
 
        if (plat != NULL) {
-               tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4);
-               twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
-               twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
+               tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
+               twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
+               twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
        } else {
                /* default timings */
-               tacls = 4;
+               tacls = tacls_max;
                twrph0 = 8;
                twrph1 = 8;
        }
 
        if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
-               printk(KERN_ERR PFX "cannot get timings suitable for board\n");
+               dev_err(info->device, "cannot get suitable timings\n");
                return -EINVAL;
        }
 
-       printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
+       dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
               tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
 
-       if (!info->is_s3c2440) {
+       switch (info->cpu_type) {
+       case TYPE_S3C2410:
                cfg = S3C2410_NFCONF_EN;
                cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
                cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
                cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
-       } else {
+               break;
+
+       case TYPE_S3C2440:
+       case TYPE_S3C2412:
                cfg = S3C2440_NFCONF_TACLS(tacls - 1);
                cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
                cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
 
                /* enable the controller and de-assert nFCE */
 
-               writel(S3C2440_NFCONT_ENABLE | S3C2440_NFCONT_ENABLE,
-                      info->regs + S3C2440_NFCONT);
+               writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
        }
 
-       pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
+       dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
 
        writel(cfg, info->regs + S3C2410_NFCONF);
        return 0;
@@ -231,26 +242,21 @@ 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;
-       void __iomem *reg;
        unsigned long cur;
-       unsigned long bit;
 
        nmtd = this->priv;
        info = nmtd->info;
 
-       bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;
-       reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF);
-
        if (chip != -1 && allow_clk_stop(info))
                clk_enable(info->clk);
 
-       cur = readl(reg);
+       cur = readl(info->sel_reg);
 
        if (chip == -1) {
-               cur |= bit;
+               cur |= info->sel_bit;
        } else {
                if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
-                       printk(KERN_ERR PFX "chip %d out of range\n", chip);
+                       dev_err(info->device, "invalid chip %d\n", chip);
                        return;
                }
 
@@ -259,10 +265,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
                                (info->platform->select_chip) (nmtd->set, chip);
                }
 
-               cur &= ~bit;
+               cur &= ~info->sel_bit;
        }
 
-       writel(cur, reg);
+       writel(cur, info->sel_reg);
 
        if (chip == -1 && allow_clk_stop(info))
                clk_disable(info->clk);
@@ -311,15 +317,25 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
 static int s3c2410_nand_devready(struct mtd_info *mtd)
 {
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-
-       if (info->is_s3c2440)
-               return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
        return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
 }
 
+static int s3c2440_nand_devready(struct mtd_info *mtd)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
+}
+
+static int s3c2412_nand_devready(struct mtd_info *mtd)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
+}
+
 /* ECC handling functions */
 
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+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);
 
@@ -487,11 +503,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
                                   struct s3c2410_nand_set *set)
 {
        struct nand_chip *chip = &nmtd->chip;
+       void __iomem *regs = info->regs;
 
-       chip->IO_ADDR_R    = info->regs + S3C2410_NFDATA;
-       chip->IO_ADDR_W    = info->regs + S3C2410_NFDATA;
-       chip->cmd_ctrl     = s3c2410_nand_hwcontrol;
-       chip->dev_ready    = s3c2410_nand_devready;
        chip->write_buf    = s3c2410_nand_write_buf;
        chip->read_buf     = s3c2410_nand_read_buf;
        chip->select_chip  = s3c2410_nand_select_chip;
@@ -500,11 +513,37 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        chip->options      = 0;
        chip->controller   = &info->controller;
 
-       if (info->is_s3c2440) {
-               chip->IO_ADDR_R  = info->regs + S3C2440_NFDATA;
-               chip->IO_ADDR_W  = info->regs + S3C2440_NFDATA;
-               chip->cmd_ctrl   = s3c2440_nand_hwcontrol;
-       }
+       switch (info->cpu_type) {
+       case TYPE_S3C2410:
+               chip->IO_ADDR_W = regs + S3C2410_NFDATA;
+               info->sel_reg   = regs + S3C2410_NFCONF;
+               info->sel_bit   = S3C2410_NFCONF_nFCE;
+               chip->cmd_ctrl  = s3c2410_nand_hwcontrol;
+               chip->dev_ready = s3c2410_nand_devready;
+               break;
+
+       case TYPE_S3C2440:
+               chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+               info->sel_reg   = regs + S3C2440_NFCONT;
+               info->sel_bit   = S3C2440_NFCONT_nFCE;
+               chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
+               chip->dev_ready = s3c2440_nand_devready;
+               break;
+
+       case TYPE_S3C2412:
+               chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+               info->sel_reg   = regs + S3C2440_NFCONT;
+               info->sel_bit   = S3C2412_NFCONT_nFCE0;
+               chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
+               chip->dev_ready = s3c2412_nand_devready;
+
+               if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
+                       dev_info(info->device, "System booted from NAND\n");
+
+               break;
+       }
+
+       chip->IO_ADDR_R = chip->IO_ADDR_W;
 
        nmtd->info         = info;
        nmtd->mtd.priv     = chip;
@@ -512,17 +551,25 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        nmtd->set          = set;
 
        if (hardware_ecc) {
-               chip->ecc.correct   = s3c2410_nand_correct_data;
-               chip->ecc.hwctl     = s3c2410_nand_enable_hwecc;
                chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+               chip->ecc.correct   = s3c2410_nand_correct_data;
                chip->ecc.mode      = NAND_ECC_HW;
                chip->ecc.size      = 512;
                chip->ecc.bytes     = 3;
                chip->ecc.layout    = &nand_hw_eccoob;
 
-               if (info->is_s3c2440) {
-                       chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
-                       chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+               switch (info->cpu_type) {
+               case TYPE_S3C2410:
+                       chip->ecc.hwctl     = s3c2410_nand_enable_hwecc;
+                       chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+                       break;
+
+               case TYPE_S3C2412:
+               case TYPE_S3C2440:
+                       chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
+                       chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+                       break;
+
                }
        } else {
                chip->ecc.mode      = NAND_ECC_SOFT;
@@ -537,7 +584,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
  * nand layer to look for devices
 */
 
-static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
+static int s3c24xx_nand_probe(struct platform_device *pdev,
+                             enum s3c_cpu_type cpu_type)
 {
        struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
        struct s3c2410_nand_info *info;
@@ -592,7 +640,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
        info->device     = &pdev->dev;
        info->platform   = plat;
        info->regs       = ioremap(res->start, size);
-       info->is_s3c2440 = is_s3c2440;
+       info->cpu_type   = cpu_type;
 
        if (info->regs == NULL) {
                dev_err(&pdev->dev, "cannot reserve register region\n");
@@ -699,12 +747,17 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
 
 static int s3c2410_nand_probe(struct platform_device *dev)
 {
-       return s3c24xx_nand_probe(dev, 0);
+       return s3c24xx_nand_probe(dev, TYPE_S3C2410);
 }
 
 static int s3c2440_nand_probe(struct platform_device *dev)
 {
-       return s3c24xx_nand_probe(dev, 1);
+       return s3c24xx_nand_probe(dev, TYPE_S3C2440);
+}
+
+static int s3c2412_nand_probe(struct platform_device *dev)
+{
+       return s3c24xx_nand_probe(dev, TYPE_S3C2412);
 }
 
 static struct platform_driver s3c2410_nand_driver = {
@@ -729,16 +782,29 @@ static struct platform_driver s3c2440_nand_driver = {
        },
 };
 
+static struct platform_driver s3c2412_nand_driver = {
+       .probe          = s3c2412_nand_probe,
+       .remove         = s3c2410_nand_remove,
+       .suspend        = s3c24xx_nand_suspend,
+       .resume         = s3c24xx_nand_resume,
+       .driver         = {
+               .name   = "s3c2412-nand",
+               .owner  = THIS_MODULE,
+       },
+};
+
 static int __init s3c2410_nand_init(void)
 {
        printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");
 
+       platform_driver_register(&s3c2412_nand_driver);
        platform_driver_register(&s3c2440_nand_driver);
        return platform_driver_register(&s3c2410_nand_driver);
 }
 
 static void __exit s3c2410_nand_exit(void)
 {
+       platform_driver_unregister(&s3c2412_nand_driver);
        platform_driver_unregister(&s3c2440_nand_driver);
        platform_driver_unregister(&s3c2410_nand_driver);
 }
index a0b4b1edcb0d10739ab6bca0f30cc85e9c62d635..f40081069ab2c6fa0f2a5705eaad7c9e698c28af 100644 (file)
@@ -97,7 +97,7 @@ static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
                unsigned long addr = TS72XX_NAND_CONTROL_VIRT_BASE;
                unsigned char bits;
 
-               bits = (ctrl & NAND_CNE) << 2;
+               bits = (ctrl & NAND_NCE) << 2;
                bits |= ctrl & NAND_CLE;
                bits |= (ctrl & NAND_ALE) >> 2;
 
index e27778926eba502acb78e7fb63c19a27a154cf60..d2f808979a2b5a9a598f45310f6fdd9ef5905b95 100644 (file)
@@ -375,8 +375,7 @@ limit of 4K.
    of the drivers, and will likely be provided by some future kernel.
 */
 enum pci_flags_bit {
-       PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-       PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+       PCI_USES_MASTER=4,
 };
 
 enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
@@ -446,95 +445,95 @@ static struct vortex_chip_info {
        int io_size;
 } vortex_info_tbl[] __devinitdata = {
        {"3c590 Vortex 10Mbps",
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c592 EISA 10Mbps Demon/Vortex",                                      /* AKPM: from Don's 3c59x_cb.c 0.49H */
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c597 EISA Fast Demon/Vortex",                                        /* AKPM: from Don's 3c59x_cb.c 0.49H */
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c595 Vortex 100baseTx",
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c595 Vortex 100baseT4",
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
 
        {"3c595 Vortex 100base-MII",
-        PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+        PCI_USES_MASTER, IS_VORTEX, 32, },
        {"3c900 Boomerang 10baseT",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
+        PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
        {"3c900 Boomerang 10Mbps Combo",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
+        PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
        {"3c900 Cyclone 10Mbps TPO",                                            /* AKPM: from Don's 0.99M */
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c900 Cyclone 10Mbps Combo",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 
        {"3c900 Cyclone 10Mbps TPC",                                            /* AKPM: from Don's 0.99M */
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c900B-FL Cyclone 10base-FL",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c905 Boomerang 100baseTx",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
+        PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
        {"3c905 Boomerang 100baseT4",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
+        PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
        {"3c905B Cyclone 100baseTx",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
 
        {"3c905B Cyclone 10/100/BNC",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3c905B-FX Cyclone 100baseFx",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
        {"3c905C Tornado",
-       PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+       PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
        {"3c920B-EMB-WNM (ATI Radeon 9100 IGP)",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
        {"3c980 Cyclone",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 
        {"3c980C Python-T",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3cSOHO100-TX Hurricane",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3c555 Laptop Hurricane",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, },
        {"3c556 Laptop Tornado",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR|
                                                                        HAS_HWCKSM, 128, },
        {"3c556B Laptop Hurricane",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
                                        WNO_XCVR_PWR|HAS_HWCKSM, 128, },
 
        {"3c575 [Megahertz] 10/100 LAN  CardBus",
-       PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
+       PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
        {"3c575 Boomerang CardBus",
-        PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
+        PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
        {"3CCFE575BT Cyclone CardBus",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|
                                                                        INVERT_LED_PWR|HAS_HWCKSM, 128, },
        {"3CCFE575CT Tornado CardBus",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
        {"3CCFE656 Cyclone CardBus",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        INVERT_LED_PWR|HAS_HWCKSM, 128, },
 
        {"3CCFEM656B Cyclone+Winmodem CardBus",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        INVERT_LED_PWR|HAS_HWCKSM, 128, },
        {"3CXFEM656C Tornado+Winmodem CardBus",                 /* From pcmcia-cs-3.1.5 */
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
                                                                        MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
        {"3c450 HomePNA Tornado",                                               /* AKPM: from Don's 0.99Q */
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3c920 Tornado",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
        {"3c982 Hydra Dual Port A",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
 
        {"3c982 Hydra Dual Port B",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
        {"3c905B-T4",
-        PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+        PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
        {"3c920B-EMB-WNM Tornado",
-        PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+        PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
 
        {NULL,}, /* NULL terminated list. */
 };
@@ -1408,8 +1407,10 @@ static int __devinit vortex_probe1(struct device *gendev,
                }
 
                if (print_info) {
-                       printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n",
-                               print_name, pci_resource_start(pdev, 2),
+                       printk(KERN_INFO "%s: CardBus functions mapped "
+                               "%16.16llx->%p\n",
+                               print_name,
+                               (unsigned long long)pci_resource_start(pdev, 2),
                                vp->cb_fn_base);
                }
                EL3WINDOW(2);
index 0cdc830449d8e58e29b772fa3cbe5f4bf8da2cb0..d26dd6a7062dcd2e72cb05a973fe1e78962fb7b4 100644 (file)
@@ -1823,7 +1823,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        struct cp_private *cp;
        int rc;
        void __iomem *regs;
-       long pciaddr;
+       resource_size_t pciaddr;
        unsigned int addr_len, i, pci_using_dac;
        u8 pci_rev;
 
@@ -1883,8 +1883,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
                rc = -EIO;
-               printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
-                      pci_resource_len(pdev, 1), pci_name(pdev));
+               printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
+                      (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
                goto err_out_res;
        }
 
@@ -1916,8 +1916,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        regs = ioremap(pciaddr, CP_REGS_SIZE);
        if (!regs) {
                rc = -EIO;
-               printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
-                      pci_resource_len(pdev, 1), pciaddr, pci_name(pdev));
+               printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%llx) on pci dev %s\n",
+                       (unsigned long long)pci_resource_len(pdev, 1),
+                       (unsigned long long)pciaddr, pci_name(pdev));
                goto err_out_res;
        }
        dev->base_addr = (unsigned long) regs;
index abd6261465f16e2692c45033ab81e3263dc6716e..ed2e3c03bc880678307b42a73b4fa61b005655c9 100644 (file)
@@ -1341,9 +1341,9 @@ static int rtl8139_open (struct net_device *dev)
        netif_start_queue (dev);
 
        if (netif_msg_ifup(tp))
-               printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d"
-                       " GP Pins %2.2x %s-duplex.\n",
-                       dev->name, pci_resource_start (tp->pci_dev, 1),
+               printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#llx IRQ %d"
+                       " GP Pins %2.2x %s-duplex.\n", dev->name,
+                       (unsigned long long)pci_resource_start (tp->pci_dev, 1),
                        dev->irq, RTL_R8 (MediaStatus),
                        tp->mii.full_duplex ? "full" : "half");
 
index 6e75482d75f266e7b81b0637343785e1b096a683..53449207e53b167f17c36567bd8de48ea03f580c 100644 (file)
@@ -683,11 +683,6 @@ struct netdev_private {
 };
 
 /* The station address location in the EEPROM. */
-#ifdef MEM_MAPPING
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-#else
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
-#endif
 /* The struct pci_device_id consist of:
         vendor, device          Vendor and device ID to match (or PCI_ANY_ID)
         subvendor, subdevice    Subsystem vendor and device ID to match (or PCI_ANY_ID)
@@ -695,9 +690,10 @@ struct netdev_private {
         class_mask              of the class are honored during the comparison.
         driver_data             Data private to the driver.
 */
-static struct pci_device_id rio_pci_tbl[] = {
-       {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {0,}
+
+static const struct pci_device_id rio_pci_tbl[] = {
+       {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
+       { }
 };
 MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
 #define TX_TIMEOUT  (4*HZ)
index 24996da4c1c44f9919b3a6277422c158c0312232..7965a9b08e797fc3e0878422ebc989c4af28b728 100644 (file)
@@ -410,10 +410,7 @@ dm9000_probe(struct platform_device *pdev)
        if (pdev->num_resources < 2) {
                ret = -ENODEV;
                goto out;
-       }
-
-       switch (pdev->num_resources) {
-       case 2:
+       } else if (pdev->num_resources == 2) {
                base = pdev->resource[0].start;
 
                if (!request_mem_region(base, 4, ndev->name)) {
@@ -423,17 +420,16 @@ dm9000_probe(struct platform_device *pdev)
 
                ndev->base_addr = base;
                ndev->irq = pdev->resource[1].start;
-               db->io_addr = (void *)base;
-               db->io_data = (void *)(base + 4);
-
-               break;
+               db->io_addr = (void __iomem *)base;
+               db->io_data = (void __iomem *)(base + 4);
 
-       case 3:
+       } else {
                db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
                db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
                db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
-               if (db->addr_res == NULL || db->data_res == NULL) {
+               if (db->addr_res == NULL || db->data_res == NULL ||
+                   db->irq_res == NULL) {
                        printk(KERN_ERR PFX "insufficient resources\n");
                        ret = -ENOENT;
                        goto out;
@@ -482,7 +478,6 @@ dm9000_probe(struct platform_device *pdev)
 
                /* ensure at least we have a default set of IO routines */
                dm9000_set_io(db, iosize);
-
        }
 
        /* check to see if anything is being over-ridden */
@@ -564,6 +559,13 @@ dm9000_probe(struct platform_device *pdev)
        for (i = 0; i < 6; i++)
                ndev->dev_addr[i] = db->srom[i];
 
+       if (!is_valid_ether_addr(ndev->dev_addr)) {
+               /* try reading from mac */
+
+               for (i = 0; i < 6; i++)
+                       ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
+       }
+
        if (!is_valid_ether_addr(ndev->dev_addr))
                printk("%s: Invalid ethernet MAC address.  Please "
                       "set using ifconfig\n", ndev->name);
@@ -663,7 +665,6 @@ dm9000_init_dm9000(struct net_device *dev)
        db->tx_pkt_cnt = 0;
        db->queue_pkt_len = 0;
        dev->trans_start = 0;
-       spin_lock_init(&db->lock);
 }
 
 /*
@@ -767,7 +768,7 @@ dm9000_stop(struct net_device *ndev)
  * receive the packet to upper layer, free the transmitted packet
  */
 
-void
+static void
 dm9000_tx_done(struct net_device *dev, board_info_t * db)
 {
        int tx_status = ior(db, DM9000_NSR);    /* Got TX status */
@@ -1187,13 +1188,14 @@ dm9000_drv_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver dm9000_driver = {
+       .driver = {
+               .name    = "dm9000",
+               .owner   = THIS_MODULE,
+       },
        .probe   = dm9000_probe,
        .remove  = dm9000_drv_remove,
        .suspend = dm9000_drv_suspend,
        .resume  = dm9000_drv_resume,
-       .driver = {
-               .name   = "dm9000",
-       },
 };
 
 static int __init
index f37170cc1a377fb3b05a17622c28c27f048fe043..93a286570923c523e118022a8024ddec68755843 100644 (file)
@@ -2678,9 +2678,9 @@ static int __devinit e100_probe(struct pci_dev *pdev,
                goto err_out_free;
        }
 
-       DPRINTK(PROBE, INFO, "addr 0x%lx, irq %d, "
+       DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
                "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
-               pci_resource_start(pdev, 0), pdev->irq,
+               (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
                netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
                netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
 
index 467fc861360d6857aa2f3828f018bbd413739e94..ecf5ad85a6847e32ac7ecb3d1eee398033cffc66 100644 (file)
@@ -278,11 +278,6 @@ having to sign an Intel NDA when I'm helping Intel sell their own product!
 
 static int speedo_found1(struct pci_dev *pdev, void __iomem *ioaddr, int fnd_cnt, int acpi_idle_state);
 
-enum pci_flags_bit {
-       PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-       PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
-};
-
 /* Offsets to the various registers.
    All accesses need not be longword aligned. */
 enum speedo_offsets {
index 724d7dc35fa3afbca55b44cd170aa2b51ecb30de..ee34a16eb4e24b8feb2667b774d5627e8168a139 100644 (file)
@@ -191,23 +191,10 @@ IVc. Errata
 */
 
 
-enum pci_id_flags_bits {
-        /* Set PCI command register bits before calling probe1(). */
-        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-        /* Read and map the single following PCI BAR. */
-        PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
-        PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-};
-
 enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 };
 
 #define EPIC_TOTAL_SIZE 0x100
 #define USE_IO_OPS 1
-#ifdef USE_IO_OPS
-#define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0
-#else
-#define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1
-#endif
 
 typedef enum {
        SMSC_83C170_0,
@@ -218,7 +205,6 @@ typedef enum {
 
 struct epic_chip_info {
        const char *name;
-       enum pci_id_flags_bits pci_flags;
         int io_size;                            /* Needed for I/O region check or ioremap(). */
         int drv_flags;                          /* Driver use, intended as capability flags. */
 };
@@ -227,11 +213,11 @@ struct epic_chip_info {
 /* indexed by chip_t */
 static const struct epic_chip_info pci_id_tbl[] = {
        { "SMSC EPIC/100 83c170",
-        EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
+         EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
        { "SMSC EPIC/100 83c170",
-        EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR },
+         EPIC_TOTAL_SIZE, TYPE2_INTR },
        { "SMSC EPIC/C 83c175",
-        EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN },
+         EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN },
 };
 
 
index a8449265e5fd5a2dbae2ffb2ee9b6ec297a3d79c..13eca7ede2af8175d524b541fd74ec60900dd5cb 100644 (file)
@@ -126,16 +126,6 @@ MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)");
 
 #define MIN_REGION_SIZE 136
 
-enum pci_flags_bit {
-       PCI_USES_IO = 1,
-       PCI_USES_MEM = 2,
-       PCI_USES_MASTER = 4,
-       PCI_ADDR0 = 0x10 << 0,
-       PCI_ADDR1 = 0x10 << 1,
-       PCI_ADDR2 = 0x10 << 2,
-       PCI_ADDR3 = 0x10 << 3,
-};
-
 /* A chip capabilities table, matching the entries in pci_tbl[] above. */
 enum chip_capability_flags {
        HAS_MII_XCVR,
index bd6983d1afbac77ed852c8991cb7b653d4272128..db694c83298961ad4630e2764cf0f7f8833098e2 100644 (file)
@@ -22,7 +22,7 @@
  * Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com)
  *
  * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
- * Copyright (c) 2004-2005 Macq Electronique SA.
+ * Copyright (c) 2004-2006 Macq Electronique SA.
  */
 
 #include <linux/config.h>
@@ -51,7 +51,7 @@
 
 #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \
     defined(CONFIG_M5272) || defined(CONFIG_M528x) || \
-    defined(CONFIG_M520x)
+    defined(CONFIG_M520x) || defined(CONFIG_M532x)
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include "fec.h"
@@ -80,6 +80,8 @@ static unsigned int fec_hw[] = {
        (MCF_MBAR + 0x1000),
 #elif defined(CONFIG_M520x)
        (MCF_MBAR+0x30000),
+#elif defined(CONFIG_M532x)
+       (MCF_MBAR+0xfc030000),
 #else
        &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec),
 #endif
@@ -143,7 +145,7 @@ typedef struct {
 #define TX_RING_MOD_MASK       15      /*   for this to work */
 
 #if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
-#error "FEC: descriptor ring size contants too large"
+#error "FEC: descriptor ring size constants too large"
 #endif
 
 /* Interrupt events/masks.
@@ -167,12 +169,12 @@ typedef struct {
 
 
 /*
- * The 5270/5271/5280/5282 RX control register also contains maximum frame
+ * The 5270/5271/5280/5282/532x 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_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
-    defined(CONFIG_M520x)
+    defined(CONFIG_M520x) || defined(CONFIG_M532x)
 #define        OPT_FRAME_SIZE  (PKT_MAXBUF_SIZE << 16)
 #else
 #define        OPT_FRAME_SIZE  0
@@ -308,6 +310,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct fec_enet_private *fep;
        volatile fec_t  *fecp;
        volatile cbd_t  *bdp;
+       unsigned short  status;
 
        fep = netdev_priv(dev);
        fecp = (volatile fec_t*)dev->base_addr;
@@ -320,8 +323,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Fill in a Tx ring entry */
        bdp = fep->cur_tx;
 
+       status = bdp->cbd_sc;
 #ifndef final_version
-       if (bdp->cbd_sc & BD_ENET_TX_READY) {
+       if (status & BD_ENET_TX_READY) {
                /* Ooops.  All transmit buffers are full.  Bail out.
                 * This should not happen, since dev->tbusy should be set.
                 */
@@ -332,7 +336,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Clear all of the status flags.
         */
-       bdp->cbd_sc &= ~BD_ENET_TX_STATS;
+       status &= ~BD_ENET_TX_STATS;
 
        /* Set buffer length and buffer pointer.
        */
@@ -366,21 +370,22 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_lock_irq(&fep->lock);
 
-       /* Send it on its way.  Tell FEC its ready, interrupt when done,
-        * its the last BD of the frame, and to put the CRC on the end.
+       /* Send it on its way.  Tell FEC it's ready, interrupt when done,
+        * it's the last BD of the frame, and to put the CRC on the end.
         */
 
-       bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
+       status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
                        | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+       bdp->cbd_sc = status;
 
        dev->trans_start = jiffies;
 
        /* Trigger transmission start */
-       fecp->fec_x_des_active = 0x01000000;
+       fecp->fec_x_des_active = 0;
 
        /* If this was the last BD in the ring, start at the beginning again.
        */
-       if (bdp->cbd_sc & BD_ENET_TX_WRAP) {
+       if (status & BD_ENET_TX_WRAP) {
                bdp = fep->tx_bd_base;
        } else {
                bdp++;
@@ -491,43 +496,44 @@ fec_enet_tx(struct net_device *dev)
 {
        struct  fec_enet_private *fep;
        volatile cbd_t  *bdp;
+       unsigned short status;
        struct  sk_buff *skb;
 
        fep = netdev_priv(dev);
        spin_lock(&fep->lock);
        bdp = fep->dirty_tx;
 
-       while ((bdp->cbd_sc&BD_ENET_TX_READY) == 0) {
+       while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
                if (bdp == fep->cur_tx && fep->tx_full == 0) break;
 
                skb = fep->tx_skbuff[fep->skb_dirty];
                /* Check for errors. */
-               if (bdp->cbd_sc & (BD_ENET_TX_HB | BD_ENET_TX_LC |
+               if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
                                   BD_ENET_TX_RL | BD_ENET_TX_UN |
                                   BD_ENET_TX_CSL)) {
                        fep->stats.tx_errors++;
-                       if (bdp->cbd_sc & BD_ENET_TX_HB)  /* No heartbeat */
+                       if (status & BD_ENET_TX_HB)  /* No heartbeat */
                                fep->stats.tx_heartbeat_errors++;
-                       if (bdp->cbd_sc & BD_ENET_TX_LC)  /* Late collision */
+                       if (status & BD_ENET_TX_LC)  /* Late collision */
                                fep->stats.tx_window_errors++;
-                       if (bdp->cbd_sc & BD_ENET_TX_RL)  /* Retrans limit */
+                       if (status & BD_ENET_TX_RL)  /* Retrans limit */
                                fep->stats.tx_aborted_errors++;
-                       if (bdp->cbd_sc & BD_ENET_TX_UN)  /* Underrun */
+                       if (status & BD_ENET_TX_UN)  /* Underrun */
                                fep->stats.tx_fifo_errors++;
-                       if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */
+                       if (status & BD_ENET_TX_CSL) /* Carrier lost */
                                fep->stats.tx_carrier_errors++;
                } else {
                        fep->stats.tx_packets++;
                }
 
 #ifndef final_version
-               if (bdp->cbd_sc & BD_ENET_TX_READY)
+               if (status & BD_ENET_TX_READY)
                        printk("HEY! Enet xmit interrupt and TX_READY.\n");
 #endif
                /* Deferred means some collisions occurred during transmit,
                 * but we eventually sent the packet OK.
                 */
-               if (bdp->cbd_sc & BD_ENET_TX_DEF)
+               if (status & BD_ENET_TX_DEF)
                        fep->stats.collisions++;
            
                /* Free the sk buffer associated with this last transmit.
@@ -538,7 +544,7 @@ fec_enet_tx(struct net_device *dev)
            
                /* Update pointer to next buffer descriptor to be transmitted.
                 */
-               if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+               if (status & BD_ENET_TX_WRAP)
                        bdp = fep->tx_bd_base;
                else
                        bdp++;
@@ -568,9 +574,14 @@ fec_enet_rx(struct net_device *dev)
        struct  fec_enet_private *fep;
        volatile fec_t  *fecp;
        volatile cbd_t *bdp;
+       unsigned short status;
        struct  sk_buff *skb;
        ushort  pkt_len;
        __u8 *data;
+       
+#ifdef CONFIG_M532x
+       flush_cache_all();
+#endif 
 
        fep = netdev_priv(dev);
        fecp = (volatile fec_t*)dev->base_addr;
@@ -580,13 +591,13 @@ fec_enet_rx(struct net_device *dev)
         */
        bdp = fep->cur_rx;
 
-while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
+while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
 
 #ifndef final_version
        /* Since we have allocated space to hold a complete frame,
         * the last indicator should be set.
         */
-       if ((bdp->cbd_sc & BD_ENET_RX_LAST) == 0)
+       if ((status & BD_ENET_RX_LAST) == 0)
                printk("FEC ENET: rcv is not +last\n");
 #endif
 
@@ -594,26 +605,26 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
                goto rx_processing_done;
 
        /* Check for errors. */
-       if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
+       if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
                           BD_ENET_RX_CR | BD_ENET_RX_OV)) {
                fep->stats.rx_errors++;       
-               if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
+               if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
                /* Frame too long or too short. */
                        fep->stats.rx_length_errors++;
                }
-               if (bdp->cbd_sc & BD_ENET_RX_NO)        /* Frame alignment */
+               if (status & BD_ENET_RX_NO)     /* Frame alignment */
                        fep->stats.rx_frame_errors++;
-               if (bdp->cbd_sc & BD_ENET_RX_CR)        /* CRC Error */
-                       fep->stats.rx_crc_errors++;
-               if (bdp->cbd_sc & BD_ENET_RX_OV)        /* FIFO overrun */
+               if (status & BD_ENET_RX_CR)     /* CRC Error */
                        fep->stats.rx_crc_errors++;
+               if (status & BD_ENET_RX_OV)     /* FIFO overrun */
+                       fep->stats.rx_fifo_errors++;
        }
 
        /* Report late collisions as a frame error.
         * On this error, the BD is closed, but we don't know what we
         * have in the buffer.  So, just drop this frame on the floor.
         */
-       if (bdp->cbd_sc & BD_ENET_RX_CL) {
+       if (status & BD_ENET_RX_CL) {
                fep->stats.rx_errors++;
                fep->stats.rx_frame_errors++;
                goto rx_processing_done;
@@ -639,9 +650,7 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
        } else {
                skb->dev = dev;
                skb_put(skb,pkt_len-4); /* Make room */
-               eth_copy_and_sum(skb,
-                                (unsigned char *)__va(bdp->cbd_bufaddr),
-                                pkt_len-4, 0);
+               eth_copy_and_sum(skb, data, pkt_len-4, 0);
                skb->protocol=eth_type_trans(skb,dev);
                netif_rx(skb);
        }
@@ -649,15 +658,16 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
 
        /* Clear the status flags for this buffer.
        */
-       bdp->cbd_sc &= ~BD_ENET_RX_STATS;
+       status &= ~BD_ENET_RX_STATS;
 
        /* Mark the buffer empty.
        */
-       bdp->cbd_sc |= BD_ENET_RX_EMPTY;
+       status |= BD_ENET_RX_EMPTY;
+       bdp->cbd_sc = status;
 
        /* Update BD pointer to next entry.
        */
-       if (bdp->cbd_sc & BD_ENET_RX_WRAP)
+       if (status & BD_ENET_RX_WRAP)
                bdp = fep->rx_bd_base;
        else
                bdp++;
@@ -667,9 +677,9 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
         * incoming frames.  On a heavily loaded network, we should be
         * able to keep up at the expense of system resources.
         */
-       fecp->fec_r_des_active = 0x01000000;
+       fecp->fec_r_des_active = 0;
 #endif
-   } /* while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) */
+   } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */
        fep->cur_rx = (cbd_t *)bdp;
 
 #if 0
@@ -680,11 +690,12 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
         * our way back to the interrupt return only to come right back
         * here.
         */
-       fecp->fec_r_des_active = 0x01000000;
+       fecp->fec_r_des_active = 0;
 #endif
 }
 
 
+/* called from interrupt context */
 static void
 fec_enet_mii(struct net_device *dev)
 {
@@ -696,10 +707,12 @@ fec_enet_mii(struct net_device *dev)
        fep = netdev_priv(dev);
        ep = fep->hwp;
        mii_reg = ep->fec_mii_data;
+
+       spin_lock(&fep->lock);
        
        if ((mip = mii_head) == NULL) {
                printk("MII and no head!\n");
-               return;
+               goto unlock;
        }
 
        if (mip->mii_func != NULL)
@@ -711,6 +724,9 @@ fec_enet_mii(struct net_device *dev)
 
        if ((mip = mii_head) != NULL)
                ep->fec_mii_data = mip->mii_regval;
+
+unlock:
+       spin_unlock(&fep->lock);
 }
 
 static int
@@ -728,8 +744,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
 
        retval = 0;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&fep->lock,flags);
 
        if ((mip = mii_free) != NULL) {
                mii_free = mip->mii_next;
@@ -749,7 +764,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
                retval = 1;
        }
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&fep->lock,flags);
 
        return(retval);
 }
@@ -1216,7 +1231,7 @@ static phy_info_t const * const phy_info[] = {
 };
 
 /* ------------------------------------------------------------------------- */
-
+#if !defined(CONFIG_M532x)
 #ifdef CONFIG_RPXCLASSIC
 static void
 mii_link_interrupt(void *dev_id);
@@ -1224,6 +1239,7 @@ mii_link_interrupt(void *dev_id);
 static irqreturn_t
 mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs);
 #endif
+#endif
 
 #if defined(CONFIG_M5272)
 
@@ -1384,13 +1400,13 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
        {
                volatile unsigned char  *icrp;
                volatile unsigned long  *imrp;
-               int i;
+               int i, ilip;
 
                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;
+               for (i = 23, ilip = 0x28; (i < 36); i++)
+                       icrp[i] = ilip--;
 
                imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
                        MCFINTC_IMRH);
@@ -1618,6 +1634,159 @@ static void __inline__ fec_uncache(unsigned long addr)
 
 /* ------------------------------------------------------------------------- */
 
+#elif defined(CONFIG_M532x)
+/*
+ * Code specific for M532x
+ */
+static void __inline__ fec_request_intrs(struct net_device *dev)
+{
+       struct fec_enet_private *fep;
+       int b;
+       static const struct idesc {
+               char *name;
+               unsigned short irq;
+       } *idp, id[] = {
+           { "fec(TXF)", 36 },
+           { "fec(TXB)", 37 },
+           { "fec(TXFIFO)", 38 },
+           { "fec(TXCR)", 39 },
+           { "fec(RXF)", 40 },
+           { "fec(RXB)", 41 },
+           { "fec(MII)", 42 },
+           { "fec(LC)", 43 },
+           { "fec(HBERR)", 44 },
+           { "fec(GRA)", 45 },
+           { "fec(EBERR)", 46 },
+           { "fec(BABT)", 47 },
+           { "fec(BABR)", 48 },
+           { NULL },
+       };
+
+       fep = netdev_priv(dev);
+       b = (fep->index) ? 128 : 64;
+
+       /* Setup interrupt handlers. */
+       for (idp = id; idp->name; idp++) {
+               if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0)
+                       printk("FEC: Could not allocate %s IRQ(%d)!\n", 
+                               idp->name, b+idp->irq);
+       }
+
+       /* Unmask interrupts */
+       MCF_INTC0_ICR36 = 0x2;
+       MCF_INTC0_ICR37 = 0x2;
+       MCF_INTC0_ICR38 = 0x2;
+       MCF_INTC0_ICR39 = 0x2;
+       MCF_INTC0_ICR40 = 0x2;
+       MCF_INTC0_ICR41 = 0x2;
+       MCF_INTC0_ICR42 = 0x2;
+       MCF_INTC0_ICR43 = 0x2;
+       MCF_INTC0_ICR44 = 0x2;
+       MCF_INTC0_ICR45 = 0x2;
+       MCF_INTC0_ICR46 = 0x2;
+       MCF_INTC0_ICR47 = 0x2;
+       MCF_INTC0_ICR48 = 0x2;
+
+       MCF_INTC0_IMRH &= ~(
+               MCF_INTC_IMRH_INT_MASK36 |
+               MCF_INTC_IMRH_INT_MASK37 |
+               MCF_INTC_IMRH_INT_MASK38 |
+               MCF_INTC_IMRH_INT_MASK39 |
+               MCF_INTC_IMRH_INT_MASK40 |
+               MCF_INTC_IMRH_INT_MASK41 |
+               MCF_INTC_IMRH_INT_MASK42 |
+               MCF_INTC_IMRH_INT_MASK43 |
+               MCF_INTC_IMRH_INT_MASK44 |
+               MCF_INTC_IMRH_INT_MASK45 |
+               MCF_INTC_IMRH_INT_MASK46 |
+               MCF_INTC_IMRH_INT_MASK47 |
+               MCF_INTC_IMRH_INT_MASK48 );
+
+       /* Set up gpio outputs for MII lines */
+       MCF_GPIO_PAR_FECI2C |= (0 |
+               MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
+               MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
+       MCF_GPIO_PAR_FEC = (0 |
+               MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
+               MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
+}
+
+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
+        */
+       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[ETH_ALEN];
+
+       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];
+       }
+
+       memcpy(dev->dev_addr, iap, ETH_ALEN);
+
+       /* Adjust MAC if using default MAC address */
+       if (iap == fec_mac_default)
+               dev->dev_addr[ETH_ALEN-1] = fec_mac_default[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 532x.
+ */
+static void __inline__ fec_uncache(unsigned long addr)
+{
+}
+
+/* ------------------------------------------------------------------------- */
+
+
 #else
 
 /*
@@ -1985,9 +2154,12 @@ fec_enet_open(struct net_device *dev)
                mii_do_cmd(dev, fep->phy->config);
                mii_do_cmd(dev, phy_cmd_config);  /* display configuration */
 
-               /* FIXME: use netif_carrier_{on,off} ; this polls
-                * until link is up which is wrong...  could be
-                * 30 seconds or more we are trapped in here. -jgarzik
+               /* Poll until the PHY tells us its configuration
+                * (not link state).
+                * Request is initiated by mii_do_cmd above, but answer
+                * comes by interrupt.
+                * This should take about 25 usec per register at 2.5 MHz,
+                * and we read approximately 5 registers.
                 */
                while(!fep->sequence_done)
                        schedule();
@@ -2253,15 +2425,11 @@ int __init fec_enet_init(struct net_device *dev)
        */
        fec_request_intrs(dev);
 
-       /* Clear and enable interrupts */
-       fecp->fec_ievent = 0xffc00000;
-       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
-               FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
        fecp->fec_hash_table_high = 0;
        fecp->fec_hash_table_low = 0;
        fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
        fecp->fec_ecntrl = 2;
-       fecp->fec_r_des_active = 0x01000000;
+       fecp->fec_r_des_active = 0;
 
        dev->base_addr = (unsigned long)fecp;
 
@@ -2281,6 +2449,11 @@ int __init fec_enet_init(struct net_device *dev)
        /* setup MII interface */
        fec_set_mii(dev, fep);
 
+       /* Clear and enable interrupts */
+       fecp->fec_ievent = 0xffc00000;
+       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
+               FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+
        /* Queue up command to detect the PHY and initialize the
         * remainder of the interface.
         */
@@ -2312,11 +2485,6 @@ fec_restart(struct net_device *dev, int duplex)
        fecp->fec_ecntrl = 1;
        udelay(10);
 
-       /* Enable interrupts we wish to service.
-       */
-       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
-                               FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
-
        /* Clear any outstanding interrupt.
        */
        fecp->fec_ievent = 0xffc00000;
@@ -2408,7 +2576,12 @@ fec_restart(struct net_device *dev, int duplex)
        /* And last, enable the transmit and receive processing.
        */
        fecp->fec_ecntrl = 2;
-       fecp->fec_r_des_active = 0x01000000;
+       fecp->fec_r_des_active = 0;
+
+       /* Enable interrupts we wish to service.
+       */
+       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
+               FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
 }
 
 static void
@@ -2420,9 +2593,16 @@ fec_stop(struct net_device *dev)
        fep = netdev_priv(dev);
        fecp = fep->hwp;
 
-       fecp->fec_x_cntrl = 0x01;       /* Graceful transmit stop */
-
-       while(!(fecp->fec_ievent & FEC_ENET_GRA));
+       /*
+       ** We cannot expect a graceful transmit stop without link !!!
+       */
+       if (fep->link)
+               {
+               fecp->fec_x_cntrl = 0x01;       /* Graceful transmit stop */
+               udelay(10);
+               if (!(fecp->fec_ievent & FEC_ENET_GRA))
+                       printk("fec_stop : Graceful transmit stop did not complete !\n");
+               }
 
        /* Whack a reset.  We should wait for this.
        */
index c6770377ef8746c384d815d5067a469d872a3b59..0cd07150bf4aeee6e3add86d7e6e5e23544c3288 100644 (file)
@@ -431,8 +431,7 @@ static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi)
        return bus;
 
 err:
-       if (bus)
-               kfree(bus);
+       kfree(bus);
        return ERR_PTR(ret);
 }
 
index 0d5fccc984bb2cf888b785447c43c4fcc19282eb..c9a46b89942af382ec10ac71f7a3710343fd0944 100644 (file)
@@ -436,7 +436,7 @@ static int __init dmascc_init(void)
 module_init(dmascc_init);
 module_exit(dmascc_exit);
 
-static void dev_setup(struct net_device *dev)
+static void __init dev_setup(struct net_device *dev)
 {
        dev->type = ARPHRD_AX25;
        dev->hard_header_len = AX25_MAX_HEADER_LEN;
index 2e4ecedba0572cc655b3827a39c88d0ddebb139b..5657049c216041faea5c59f61e37898643f14447 100644 (file)
@@ -226,7 +226,6 @@ static int full_duplex[MAX_UNITS];
                                 NATSEMI_PG1_NREGS)
 #define NATSEMI_REGS_VER       1 /* v1 added RFDR registers */
 #define NATSEMI_REGS_SIZE      (NATSEMI_NREGS * sizeof(u32))
-#define NATSEMI_DEF_EEPROM_SIZE        24 /* 12 16-bit values */
 
 /* Buffer sizes:
  * The nic writes 32-bit values, even if the upper bytes of
@@ -344,18 +343,6 @@ None characterised.
 
 
 
-enum pcistuff {
-       PCI_USES_IO = 0x01,
-       PCI_USES_MEM = 0x02,
-       PCI_USES_MASTER = 0x04,
-       PCI_ADDR0 = 0x08,
-       PCI_ADDR1 = 0x10,
-};
-
-/* MMIO operations required */
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-
-
 /*
  * Support for fibre connections on Am79C874:
  * This phy needs a special setup when connected to a fibre cable.
@@ -363,22 +350,25 @@ enum pcistuff {
  */
 #define PHYID_AM79C874 0x0022561b
 
-#define MII_MCTRL      0x15    /* mode control register */
-#define MII_FX_SEL     0x0001  /* 100BASE-FX (fiber) */
-#define MII_EN_SCRM    0x0004  /* enable scrambler (tp) */
+enum {
+       MII_MCTRL       = 0x15,         /* mode control register */
+       MII_FX_SEL      = 0x0001,       /* 100BASE-FX (fiber) */
+       MII_EN_SCRM     = 0x0004,       /* enable scrambler (tp) */
+};
 
  
 /* array of board data directly indexed by pci_tbl[x].driver_data */
 static const struct {
        const char *name;
        unsigned long flags;
+       unsigned int eeprom_size;
 } natsemi_pci_info[] __devinitdata = {
-       { "NatSemi DP8381[56]", PCI_IOTYPE },
+       { "NatSemi DP8381[56]", 0, 24 },
 };
 
-static struct pci_device_id natsemi_pci_tbl[] = {
-       { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815, PCI_ANY_ID, PCI_ANY_ID, },
-       { 0, },
+static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
+       { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { }     /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl);
 
@@ -813,6 +803,42 @@ static void move_int_phy(struct net_device *dev, int addr)
        udelay(1);
 }
 
+static void __devinit natsemi_init_media (struct net_device *dev)
+{
+       struct netdev_private *np = netdev_priv(dev);
+       u32 tmp;
+
+       netif_carrier_off(dev);
+
+       /* get the initial settings from hardware */
+       tmp            = mdio_read(dev, MII_BMCR);
+       np->speed      = (tmp & BMCR_SPEED100)? SPEED_100     : SPEED_10;
+       np->duplex     = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL   : DUPLEX_HALF;
+       np->autoneg    = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE;
+       np->advertising= mdio_read(dev, MII_ADVERTISE);
+
+       if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL
+        && netif_msg_probe(np)) {
+               printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s "
+                       "10%s %s duplex.\n",
+                       pci_name(np->pci_dev),
+                       (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)?
+                         "enabled, advertise" : "disabled, force",
+                       (np->advertising &
+                         (ADVERTISE_100FULL|ADVERTISE_100HALF))?
+                           "0" : "",
+                       (np->advertising &
+                         (ADVERTISE_100FULL|ADVERTISE_10FULL))?
+                           "full" : "half");
+       }
+       if (netif_msg_probe(np))
+               printk(KERN_INFO
+                       "natsemi %s: Transceiver status %#04x advertising %#04x.\n",
+                       pci_name(np->pci_dev), mdio_read(dev, MII_BMSR),
+                       np->advertising);
+
+}
+
 static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        const struct pci_device_id *ent)
 {
@@ -852,8 +878,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        iosize = pci_resource_len(pdev, pcibar);
        irq = pdev->irq;
 
-       if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER)
-               pci_set_master(pdev);
+       pci_set_master(pdev);
 
        dev = alloc_etherdev(sizeof (struct netdev_private));
        if (!dev)
@@ -892,7 +917,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG;
        np->hands_off = 0;
        np->intr_status = 0;
-       np->eeprom_size = NATSEMI_DEF_EEPROM_SIZE;
+       np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size;
 
        /* Initial port:
         * - If the nic was configured to use an external phy and if find_mii
@@ -957,34 +982,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        if (mtu)
                dev->mtu = mtu;
 
-       netif_carrier_off(dev);
-
-       /* get the initial settings from hardware */
-       tmp            = mdio_read(dev, MII_BMCR);
-       np->speed      = (tmp & BMCR_SPEED100)? SPEED_100     : SPEED_10;
-       np->duplex     = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL   : DUPLEX_HALF;
-       np->autoneg    = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE;
-       np->advertising= mdio_read(dev, MII_ADVERTISE);
-
-       if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL
-        && netif_msg_probe(np)) {
-               printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s "
-                       "10%s %s duplex.\n",
-                       pci_name(np->pci_dev),
-                       (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)?
-                         "enabled, advertise" : "disabled, force",
-                       (np->advertising &
-                         (ADVERTISE_100FULL|ADVERTISE_100HALF))?
-                           "0" : "",
-                       (np->advertising &
-                         (ADVERTISE_100FULL|ADVERTISE_10FULL))?
-                           "full" : "half");
-       }
-       if (netif_msg_probe(np))
-               printk(KERN_INFO
-                       "natsemi %s: Transceiver status %#04x advertising %#04x.\n",
-                       pci_name(np->pci_dev), mdio_read(dev, MII_BMSR),
-                       np->advertising);
+       natsemi_init_media(dev);
 
        /* save the silicon revision for later querying */
        np->srr = readl(ioaddr + SiliconRev);
index fc08c4af506ca8194b7f4d3854181fdc5eed43b4..0e01c75da4296647884603414f9002fea6834e2a 100644 (file)
@@ -309,12 +309,6 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name);
 static void pcnet32_free_ring(struct net_device *dev);
 static void pcnet32_check_media(struct net_device *dev, int verbose);
 
-enum pci_flags_bit {
-       PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4,
-       PCI_ADDR0 = 0x10 << 0, PCI_ADDR1 = 0x10 << 1, PCI_ADDR2 =
-           0x10 << 2, PCI_ADDR3 = 0x10 << 3,
-};
-
 static u16 pcnet32_wio_read_csr(unsigned long addr, int index)
 {
        outw(index, addr + PCNET32_WIO_RAP);
index bef79e454c337c0c3d9bf5b1f365be56470b94a9..3f702c503afe9377aeddb835c9c9eb7c8707665a 100644 (file)
@@ -123,9 +123,9 @@ static int lxt971_config_intr(struct phy_device *phydev)
 }
 
 static struct phy_driver lxt970_driver = {
-       .phy_id         = 0x07810000,
+       .phy_id         = 0x78100000,
        .name           = "LXT970",
-       .phy_id_mask    = 0x0fffffff,
+       .phy_id_mask    = 0xfffffff0,
        .features       = PHY_BASIC_FEATURES,
        .flags          = PHY_HAS_INTERRUPT,
        .config_init    = lxt970_config_init,
@@ -137,9 +137,9 @@ static struct phy_driver lxt970_driver = {
 };
 
 static struct phy_driver lxt971_driver = {
-       .phy_id         = 0x0001378e,
+       .phy_id         = 0x001378e0,
        .name           = "LXT971",
-       .phy_id_mask    = 0x0fffffff,
+       .phy_id_mask    = 0xfffffff0,
        .features       = PHY_BASIC_FEATURES,
        .flags          = PHY_HAS_INTERRUPT,
        .config_aneg    = genphy_config_aneg,
index d643a097faa5cd8de1a234179d17ab55aa336ed3..425ff5b117f1c3e2da4338ee44e9dbce25f318fe 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/netdevice.h>
 #include <linux/poll.h>
 #include <linux/ppp_defs.h>
@@ -863,10 +862,6 @@ static int __init ppp_init(void)
                        goto out_chrdev;
                }
                class_device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
-               err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0),
-                               S_IFCHR|S_IRUSR|S_IWUSR, "ppp");
-               if (err)
-                       goto out_class;
        }
 
 out:
@@ -874,9 +869,6 @@ out:
                printk(KERN_ERR "failed to register PPP device (%d)\n", err);
        return err;
 
-out_class:
-       class_device_destroy(ppp_class, MKDEV(PPP_MAJOR,0));
-       class_destroy(ppp_class);
 out_chrdev:
        unregister_chrdev(PPP_MAJOR, "ppp");
        goto out;
@@ -2681,7 +2673,6 @@ static void __exit ppp_cleanup(void)
        cardmap_destroy(&all_ppp_units);
        if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
                printk(KERN_ERR "PPP: failed to unregister PPP device\n");
-       devfs_remove("ppp");
        class_device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
        class_destroy(ppp_class);
 }
index 19a4a16055dc2435e13a0103d90663dde5485ac4..1608efab4e3de39c914dfb964dfbd767a2ccea4b 100644 (file)
@@ -3354,8 +3354,8 @@ static int __devinit skge_probe(struct pci_dev *pdev,
        if (err)
                goto err_out_free_irq;
 
-       printk(KERN_INFO PFX DRV_VERSION " addr 0x%lx irq %d chip %s rev %d\n",
-              pci_resource_start(pdev, 0), pdev->irq,
+       printk(KERN_INFO PFX DRV_VERSION " addr 0x%llx irq %d chip %s rev %d\n",
+              (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
               skge_board_name(hw), hw->chip_rev);
 
        if ((dev = skge_devinit(hw, 0, using_dac)) == NULL)
index d3577871be28ddc3897d835a59f5f83fbc6b3c0f..e122007e16da08b599d5644a503f34b2f359758f 100644 (file)
@@ -3311,9 +3311,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
        if (err)
                goto err_out_iounmap;
 
-       printk(KERN_INFO PFX "v%s addr 0x%lx irq %d Yukon-%s (0x%x) rev %d\n",
-              DRV_VERSION, pci_resource_start(pdev, 0), pdev->irq,
-              yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
+       printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
+              DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
+              pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
               hw->chip_id, hw->chip_rev);
 
        dev = sky2_init_netdev(hw, 0, using_dac);
index 5f743b972949930929335ed20fb55288d47b1dd1..fc2468ecce0b1db743e8158d07468c15f1eca80c 100644 (file)
@@ -2007,8 +2007,8 @@ static int __init de_init_one (struct pci_dev *pdev,
        }
        if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) {
                rc = -EIO;
-               printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
-                      pci_resource_len(pdev, 1), pci_name(pdev));
+               printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
+                      (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
                goto err_out_res;
        }
 
@@ -2016,8 +2016,9 @@ static int __init de_init_one (struct pci_dev *pdev,
        regs = ioremap_nocache(pciaddr, DE_REGS_SIZE);
        if (!regs) {
                rc = -EIO;
-               printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
-                      pci_resource_len(pdev, 1), pciaddr, pci_name(pdev));
+               printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
+                       (unsigned long long)pci_resource_len(pdev, 1),
+                       pciaddr, pci_name(pdev));
                goto err_out_res;
        }
        dev->base_addr = (unsigned long) regs;
index e0de66739a422744616ae3205e89db5504f2036c..53fd9b56d0bd7967b51cbf794128c1c15918979b 100644 (file)
@@ -1350,10 +1350,10 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
        if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
-               printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) too small, "
+               printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, "
                        "aborting\n", pci_name(pdev),
-                       pci_resource_len (pdev, 0),
-                       pci_resource_start (pdev, 0));
+                       (unsigned long long)pci_resource_len (pdev, 0),
+                       (unsigned long long)pci_resource_start (pdev, 0));
                goto err_out_free_netdev;
        }
 
index 8fea2aa455d4690a10763f7a4dc070c755a9c3d0..602a6e5002a076fcefb64a04742535c2012e8b4d 100644 (file)
@@ -212,26 +212,15 @@ Test with 'ping -s 10000' on a fast computer.
 /*
   PCI probe table.
 */
-enum pci_id_flags_bits {
-        /* Set PCI command register bits before calling probe1(). */
-        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-        /* Read and map the single following PCI BAR. */
-        PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
-        PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-};
 enum chip_capability_flags {
-       CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,};
-#ifdef USE_IO_OPS
-#define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
-#else
-#define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
-#endif
+       CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,
+};
 
-static struct pci_device_id w840_pci_tbl[] = {
+static const struct pci_device_id w840_pci_tbl[] = {
        { 0x1050, 0x0840, PCI_ANY_ID, 0x8153,     0, 0, 0 },
        { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
        { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
-       { 0, }
+       { }
 };
 MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
 
@@ -241,18 +230,17 @@ struct pci_id_info {
                 int     pci, pci_mask, subsystem, subsystem_mask;
                 int revision, revision_mask;                            /* Only 8 bits. */
         } id;
-        enum pci_id_flags_bits pci_flags;
         int io_size;                            /* Needed for I/O region check or ioremap(). */
         int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 static struct pci_id_info pci_id_tbl[] = {
        {"Winbond W89c840",                     /* Sometime a Level-One switch card. */
         { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
-        W840_FLAGS, 128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
+          128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
        {"Winbond W89c840", { 0x08401050, 0xffffffff, },
-        W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
+          128, CanHaveMII | HasBrokenTx},
        {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
-        W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
+          128, CanHaveMII | HasBrokenTx},
        {NULL,},                                        /* 0 terminated list. */
 };
 
index 6c62d5c882683f09267e06e9dade80f1cfb9482d..732c5edec2e5edd3cab20c8d0aa43233b8fab8c8 100644 (file)
@@ -780,7 +780,6 @@ static struct miscdevice tun_miscdev = {
        .minor = TUN_MINOR,
        .name = "tun",
        .fops = &tun_fops,
-       .devfs_name = "net/tun",
 };
 
 /* ethtool interface */
index e49e8b520c28120f9aaa346d80b310a5b6e2814b..e24d2dafcf6c3695662c4ea3cdb8ece7cd672e38 100644 (file)
@@ -2568,9 +2568,10 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_drvdata(pdev, dev);
 
-       printk(KERN_INFO "%s: %s at %s 0x%lx, ",
+       printk(KERN_INFO "%s: %s at %s 0x%llx, ",
               dev->name, typhoon_card_info[card_id].name,
-              use_mmio ? "MMIO" : "IO", pci_resource_start(pdev, use_mmio));
+              use_mmio ? "MMIO" : "IO",
+              (unsigned long long)pci_resource_start(pdev, use_mmio));
        for(i = 0; i < 5; i++)
                printk("%2.2x:", dev->dev_addr[i]);
        printk("%2.2x\n", dev->dev_addr[i]);
index b60ef02db7b06b6a8868fce2e4ec44fb304b6eb9..c92ac9fde0831ff6175f17bc45bfdb1876c158e3 100644 (file)
@@ -7,7 +7,7 @@
  * under the terms of version 2 of the GNU General Public License
  * as published by the Free Software Foundation.
  *
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
  *
  * Sources of information:
  *    Hitachi HD64570 SCA User's Manual
index e392ee8b37a14828e02b8fc9198d8f8ab0618747..be5e33814cb144ea7db78787342c6dda1e7e0a08 100644 (file)
@@ -85,7 +85,6 @@
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -393,7 +392,6 @@ static int __init cosa_init(void)
                err = -ENODEV;
                goto out;
        }
-       devfs_mk_dir("cosa");
        cosa_class = class_create(THIS_MODULE, "cosa");
        if (IS_ERR(cosa_class)) {
                err = PTR_ERR(cosa_class);
@@ -402,13 +400,6 @@ static int __init cosa_init(void)
        for (i=0; i<nr_cards; i++) {
                class_device_create(cosa_class, NULL, MKDEV(cosa_major, i),
                                NULL, "cosa%d", i);
-               err = devfs_mk_cdev(MKDEV(cosa_major, i),
-                               S_IFCHR|S_IRUSR|S_IWUSR,
-                               "cosa/%d", i);
-               if (err) {
-                       class_device_destroy(cosa_class, MKDEV(cosa_major, i));
-                       goto out_chrdev;                
-               }
        }
        err = 0;
        goto out;
@@ -426,12 +417,9 @@ static void __exit cosa_exit(void)
        int i;
        printk(KERN_INFO "Unloading the cosa module\n");
 
-       for (i=0; i<nr_cards; i++) {
+       for (i=0; i<nr_cards; i++)
                class_device_destroy(cosa_class, MKDEV(cosa_major, i));
-               devfs_remove("cosa/%d", i);
-       }
        class_destroy(cosa_class);
-       devfs_remove("cosa");
        for (cosa=cosa_cards; nr_cards--; cosa++) {
                /* Clean up the per-channel data */
                for (i=0; i<cosa->nchannels; i++) {
index 4505540e3c591611182645433ac5dbc353e07a2a..04a376ec0ed84ab737c373342914ed172a4b1129 100644 (file)
@@ -732,15 +732,15 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev,
        ioaddr = ioremap(pci_resource_start(pdev, 0),
                                        pci_resource_len(pdev, 0));
        if (!ioaddr) {
-               printk(KERN_ERR "%s: cannot remap MMIO region %lx @ %lx\n",
-                       DRV_NAME, pci_resource_len(pdev, 0),
-                       pci_resource_start(pdev, 0));
+               printk(KERN_ERR "%s: cannot remap MMIO region %llx @ %llx\n",
+                       DRV_NAME, (unsigned long long)pci_resource_len(pdev, 0),
+                       (unsigned long long)pci_resource_start(pdev, 0));
                rc = -EIO;
                goto err_free_mmio_regions_2;
        }
-       printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d\n",
-               pci_resource_start(pdev, 0),
-               pci_resource_start(pdev, 1), pdev->irq);
+       printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#llx (regs), %#llx (lbi), IRQ %d\n",
+               (unsigned long long)pci_resource_start(pdev, 0),
+               (unsigned long long)pci_resource_start(pdev, 1), pdev->irq);
 
        /* Cf errata DS5 p.2 */
        pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8);
index b7d88db89a5c7918e5a827aeb6465cab7b5411a7..e013b817cab8dbb22fd1df3f426b45d3d260e223 100644 (file)
@@ -7,7 +7,7 @@
  * under the terms of version 2 of the GNU General Public License
  * as published by the Free Software Foundation.
  *
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
  *
  * Note: integrated CSU/DSU/DDS are not supported by this driver
  *
index a3e65d1bc19bbcddda71bd74f2ec707a6a0bf5f1..d7897ae89f904dc906250c67cdde073f2243e7ed 100644 (file)
@@ -3445,9 +3445,9 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        card = (pc300_t *) kmalloc(sizeof(pc300_t), GFP_KERNEL);
        if (card == NULL) {
-               printk("PC300 found at RAM 0x%08lx, "
+               printk("PC300 found at RAM 0x%016llx, "
                       "but could not allocate card structure.\n",
-                      pci_resource_start(pdev, 3));
+                      (unsigned long long)pci_resource_start(pdev, 3));
                err = -ENOMEM;
                goto err_disable_dev;
        }
index 670e8bd2245c7fef651df170cf889fc8e33c4f51..24c3c57c13c933d90f50933d1540791425d61f13 100644 (file)
@@ -7,7 +7,7 @@
  * under the terms of version 2 of the GNU General Public License
  * as published by the Free Software Foundation.
  *
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
  *
  * Sources of information:
  *    Hitachi HD64572 SCA-II User's Manual
index 081a8999666e7e168404141073c687d0af2dfe0b..a8a8f975432fe1e32a3fb04aa0a4bc2d59d94e24 100644 (file)
@@ -1229,12 +1229,6 @@ static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
        return error;
 }
 
-static void ipw_free_error_log(struct ipw_fw_error *error)
-{
-       if (error)
-               kfree(error);
-}
-
 static ssize_t show_event_log(struct device *d,
                              struct device_attribute *attr, char *buf)
 {
@@ -1296,10 +1290,9 @@ static ssize_t clear_error(struct device *d,
                           const char *buf, size_t count)
 {
        struct ipw_priv *priv = dev_get_drvdata(d);
-       if (priv->error) {
-               ipw_free_error_log(priv->error);
-               priv->error = NULL;
-       }
+
+       kfree(priv->error);
+       priv->error = NULL;
        return count;
 }
 
@@ -1970,8 +1963,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
                                struct ipw_fw_error *error =
                                    ipw_alloc_error_log(priv);
                                ipw_dump_error_log(priv, error);
-                               if (error)
-                                       ipw_free_error_log(error);
+                               kfree(error);
                        }
 #endif
                } else {
@@ -11693,10 +11685,8 @@ static void ipw_pci_remove(struct pci_dev *pdev)
                }
        }
 
-       if (priv->error) {
-               ipw_free_error_log(priv->error);
-               priv->error = NULL;
-       }
+       kfree(priv->error);
+       priv->error = NULL;
 
 #ifdef CONFIG_IPW2200_PROMISCUOUS
        ipw_prom_free(priv);
index ecec8e5db786e66dc4128edd216d8cb8a0072eb8..569305f57561fd5304a3ae73b490f78edebfe380 100644 (file)
@@ -234,14 +234,6 @@ See Packet Engines confidential appendix (prototype chips only).
 
 \f
 
-enum pci_id_flags_bits {
-       /* Set PCI command register bits before calling probe1(). */
-       PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-       /* Read and map the single following PCI BAR. */
-       PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
-       PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-       PCI_UNUSED_IRQ=0x800,
-};
 enum capability_flags {
        HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
        HasMACAddrBug=32, /* Only on early revs.  */
@@ -249,11 +241,6 @@ enum capability_flags {
 };
 /* The PCI I/O space extent. */
 #define YELLOWFIN_SIZE 0x100
-#ifdef USE_IO_OPS
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
-#else
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-#endif
 
 struct pci_id_info {
         const char *name;
@@ -261,24 +248,23 @@ struct pci_id_info {
                 int     pci, pci_mask, subsystem, subsystem_mask;
                 int revision, revision_mask;                            /* Only 8 bits. */
         } id;
-        enum pci_id_flags_bits pci_flags;
         int io_size;                            /* Needed for I/O region check or ioremap(). */
         int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 
 static const struct pci_id_info pci_id_tbl[] = {
        {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
-        PCI_IOTYPE, YELLOWFIN_SIZE,
+        YELLOWFIN_SIZE,
         FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom},
        {"Symbios SYM83C885", { 0x07011000, 0xffffffff},
-        PCI_IOTYPE, YELLOWFIN_SIZE, HasMII | DontUseEeprom },
-       {NULL,},
+        YELLOWFIN_SIZE, HasMII | DontUseEeprom },
+       { }
 };
 
-static struct pci_device_id yellowfin_pci_tbl[] = {
+static const struct pci_device_id yellowfin_pci_tbl[] = {
        { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
-       { 0, }
+       { }
 };
 MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl);
 
index 3f5de867acd7cb4b9dd7229194e8c14f7bdea840..1d3b84b4af3fc5fb0937763098f7f65e57fb80fd 100644 (file)
@@ -140,18 +140,37 @@ config CHASSIS_LCD_LED
          If unsure, say Y.
 
 config PDC_CHASSIS
-       bool "PDC chassis State Panel support"
+       bool "PDC chassis state codes support"
        default y
        help
-         Say Y here if you want to enable support for the LED State front
-         panel as found on E class, and support for the GSP Virtual Front
-         Panel (LED State and message logging)  as found on high end
-         servers such as A, L and N-class.
-         
-         This has nothing to do with Chassis LCD and LED support.
+         Say Y here if you want to enable support for Chassis codes.
+         That includes support for LED State front panel as found on E
+         class, and support for the GSP Virtual Front Panel (LED State and
+         message logging)  as found on high end servers such as A, L and
+         N-class.
+         This driver will also display progress messages on LCD display,
+         such as "INI", "RUN" and "FLT", and might thus clobber messages
+         shown by the LED/LCD driver.
+         This driver updates the state panel (LED and/or LCD) upon system
+         state change (eg: boot, shutdown or panic).
          
          If unsure, say Y.
 
+
+config PDC_CHASSIS_WARN
+       bool "PDC chassis warnings support"
+       depends on PROC_FS
+       default y
+       help
+         Say Y here if you want to enable support for Chassis warnings.
+         This will add a proc entry '/proc/chassis' giving some information
+         about the overall health state of the system.
+         This includes NVRAM battery level, overtemp or failures such as
+         fans or power units.
+
+         If unsure, say Y.
+
+
 config PDC_STABLE
        tristate "PDC Stable Storage support"
        depends on SYSFS
index 6e8ed0c81a6cbd5883fafa74b940e77077d9cee7..ce0a6ebcff15dfa74a4ff8e8812878078a8e46a9 100644 (file)
@@ -299,7 +299,7 @@ struct pci_port_ops dino_port_ops = {
 
 static void dino_disable_irq(unsigned int irq)
 {
-       struct dino_device *dino_dev = irq_desc[irq].handler_data;
+       struct dino_device *dino_dev = irq_desc[irq].chip_data;
        int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
 
        DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq);
@@ -311,7 +311,7 @@ static void dino_disable_irq(unsigned int irq)
 
 static void dino_enable_irq(unsigned int irq)
 {
-       struct dino_device *dino_dev = irq_desc[irq].handler_data;
+       struct dino_device *dino_dev = irq_desc[irq].chip_data;
        int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
        u32 tmp;
 
index 9d3bd15bf53be98c071b2c7d7585ba689974b6f9..58f0ce8d78e066c2f75fb63371924db5f41f549f 100644 (file)
@@ -350,7 +350,7 @@ static int __devinit eisa_probe(struct parisc_device *dev)
        irq_desc[2].action = &irq2_action;
        
        for (i = 0; i < 16; i++) {
-               irq_desc[i].handler = &eisa_interrupt_type;
+               irq_desc[i].chip = &eisa_interrupt_type;
        }
        
        EISA_bus = 1;
index 16d40f95978d135d8cf310efff612094c1e6d451..5476ba7709b3cc4a9a7aec1612d74be7898a0f83 100644 (file)
@@ -109,7 +109,7 @@ int gsc_find_local_irq(unsigned int irq, int *global_irqs, int limit)
 
 static void gsc_asic_disable_irq(unsigned int irq)
 {
-       struct gsc_asic *irq_dev = irq_desc[irq].handler_data;
+       struct gsc_asic *irq_dev = irq_desc[irq].chip_data;
        int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
        u32 imr;
 
@@ -124,7 +124,7 @@ static void gsc_asic_disable_irq(unsigned int irq)
 
 static void gsc_asic_enable_irq(unsigned int irq)
 {
-       struct gsc_asic *irq_dev = irq_desc[irq].handler_data;
+       struct gsc_asic *irq_dev = irq_desc[irq].chip_data;
        int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
        u32 imr;
 
@@ -164,8 +164,8 @@ int gsc_assign_irq(struct hw_interrupt_type *type, void *data)
        if (irq > GSC_IRQ_MAX)
                return NO_IRQ;
 
-       irq_desc[irq].handler = type;
-       irq_desc[irq].handler_data = data;
+       irq_desc[irq].chip = type;
+       irq_desc[irq].chip_data = data;
        return irq++;
 }
 
index 7a458d5bc75134d925aa272b34af805f1646384e..1fbda77cefc29bfb0bbe820314feabce0d2c9700 100644 (file)
@@ -619,7 +619,7 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
 
 static struct vector_info *iosapic_get_vector(unsigned int irq)
 {
-       return irq_desc[irq].handler_data;
+       return irq_desc[irq].chip_data;
 }
 
 static void iosapic_disable_irq(unsigned int irq)
index bbeabe3fc4c6788984f3bd9567b3543681c1bf5a..ea1b7a63598e1c4fc87ee001a66293cb2fe92b37 100644 (file)
  *    following code can deal with just 96 bytes of Stable Storage, and all
  *    sizes between 96 and 192 bytes (provided they are multiple of struct
  *    device_path size, eg: 128, 160 and 192) to provide full information.
- *    The code makes no use of data above 192 bytes. One last word: there's one
- *    path we can always count on: the primary path.
+ *    One last word: there's one path we can always count on: the primary path.
+ *    Anything above 224 bytes is used for 'osdep2' OS-dependent storage area.
+ *
+ *    The first OS-dependent area should always be available. Obviously, this is
+ *    not true for the other one. Also bear in mind that reading/writing from/to
+ *    osdep2 is much more expensive than from/to osdep1.
+ *    NOTE: We do not handle the 2 bytes OS-dep area at 0x5D, nor the first
+ *    2 bytes of storage available right after OSID. That's a total of 4 bytes
+ *    sacrificed: -ETOOLAZY :P
  *
  *    The current policy wrt file permissions is:
  *     - write: root only
 #include <asm/uaccess.h>
 #include <asm/hardware.h>
 
-#define PDCS_VERSION   "0.22"
+#define PDCS_VERSION   "0.30"
 #define PDCS_PREFIX    "PDC Stable Storage"
 
 #define PDCS_ADDR_PPRI 0x00
 #define PDCS_ADDR_OSID 0x40
+#define PDCS_ADDR_OSD1 0x48
+#define PDCS_ADDR_DIAG 0x58
 #define PDCS_ADDR_FSIZ 0x5C
 #define PDCS_ADDR_PCON 0x60
 #define PDCS_ADDR_PALT 0x80
 #define PDCS_ADDR_PKBD 0xA0
+#define PDCS_ADDR_OSD2 0xE0
 
 MODULE_AUTHOR("Thibaut VARENE <varenet@parisc-linux.org>");
 MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data");
@@ -82,6 +92,9 @@ MODULE_VERSION(PDCS_VERSION);
 /* holds Stable Storage size. Initialized once and for all, no lock needed */
 static unsigned long pdcs_size __read_mostly;
 
+/* holds OS ID. Initialized once and for all, hopefully to 0x0006 */
+static u16 pdcs_osid __read_mostly;
+
 /* This struct defines what we need to deal with a parisc pdc path entry */
 struct pdcspath_entry {
        rwlock_t rw_lock;               /* to protect path entry access */
@@ -609,27 +622,64 @@ static ssize_t
 pdcs_osid_read(struct subsystem *entry, char *buf)
 {
        char *out = buf;
-       __u32 result;
-       char *tmpstr = NULL;
 
        if (!entry || !buf)
                return -EINVAL;
 
-       /* get OSID */
-       if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
+       out += sprintf(out, "%s dependent data (0x%.4x)\n",
+               os_id_to_string(pdcs_osid), pdcs_osid);
+
+       return out - buf;
+}
+
+/**
+ * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * This can hold 16 bytes of OS-Dependent data.
+ */
+static ssize_t
+pdcs_osdep1_read(struct subsystem *entry, char *buf)
+{
+       char *out = buf;
+       u32 result[4];
+
+       if (!entry || !buf)
+               return -EINVAL;
+
+       if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
                return -EIO;
 
-       /* the actual result is 16 bits away */
-       switch (result >> 16) {
-               case 0x0000:    tmpstr = "No OS-dependent data"; break;
-               case 0x0001:    tmpstr = "HP-UX dependent data"; break;
-               case 0x0002:    tmpstr = "MPE-iX dependent data"; break;
-               case 0x0003:    tmpstr = "OSF dependent data"; break;
-               case 0x0004:    tmpstr = "HP-RT dependent data"; break;
-               case 0x0005:    tmpstr = "Novell Netware dependent data"; break;
-               default:        tmpstr = "Unknown"; break;
-       }
-       out += sprintf(out, "%s (0x%.4x)\n", tmpstr, (result >> 16));
+       out += sprintf(out, "0x%.8x\n", result[0]);
+       out += sprintf(out, "0x%.8x\n", result[1]);
+       out += sprintf(out, "0x%.8x\n", result[2]);
+       out += sprintf(out, "0x%.8x\n", result[3]);
+
+       return out - buf;
+}
+
+/**
+ * pdcs_diagnostic_read - Stable Storage Diagnostic register output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * I have NFC how to interpret the content of that register ;-).
+ */
+static ssize_t
+pdcs_diagnostic_read(struct subsystem *entry, char *buf)
+{
+       char *out = buf;
+       u32 result;
+
+       if (!entry || !buf)
+               return -EINVAL;
+
+       /* get diagnostic */
+       if (pdc_stable_read(PDCS_ADDR_DIAG, &result, sizeof(result)) != PDC_OK)
+               return -EIO;
+
+       out += sprintf(out, "0x%.4x\n", (result >> 16));
 
        return out - buf;
 }
@@ -645,7 +695,7 @@ static ssize_t
 pdcs_fastsize_read(struct subsystem *entry, char *buf)
 {
        char *out = buf;
-       __u32 result;
+       u32 result;
 
        if (!entry || !buf)
                return -EINVAL;
@@ -663,6 +713,39 @@ pdcs_fastsize_read(struct subsystem *entry, char *buf)
        return out - buf;
 }
 
+/**
+ * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
+ */
+static ssize_t
+pdcs_osdep2_read(struct subsystem *entry, char *buf)
+{
+       char *out = buf;
+       unsigned long size;
+       unsigned short i;
+       u32 result;
+
+       if (unlikely(pdcs_size <= 224))
+               return -ENODATA;
+
+       size = pdcs_size - 224;
+
+       if (!entry || !buf)
+               return -EINVAL;
+
+       for (i=0; i<size; i+=4) {
+               if (unlikely(pdc_stable_read(PDCS_ADDR_OSD2 + i, &result,
+                                       sizeof(result)) != PDC_OK))
+                       return -EIO;
+               out += sprintf(out, "0x%.8x\n", result);
+       }
+
+       return out - buf;
+}
+
 /**
  * pdcs_auto_write - This function handles autoboot/search flag modifying.
  * @entry: An allocated and populated subsytem struct. We don't use it tho.
@@ -770,13 +853,100 @@ pdcs_autosearch_write(struct subsystem *entry, const char *buf, size_t count)
        return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH);
 }
 
+/**
+ * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ *
+ * This can store 16 bytes of OS-Dependent data. We use a byte-by-byte
+ * write approach. It's up to userspace to deal with it when constructing
+ * its input buffer.
+ */
+static ssize_t
+pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count)
+{
+       u8 in[16];
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (!entry || !buf || !count)
+               return -EINVAL;
+
+       if (unlikely(pdcs_osid != OS_ID_LINUX))
+               return -EPERM;
+
+       if (count > 16)
+               return -EMSGSIZE;
+
+       /* We'll use a local copy of buf */
+       memset(in, 0, 16);
+       memcpy(in, buf, count);
+
+       if (pdc_stable_write(PDCS_ADDR_OSD1, &in, sizeof(in)) != PDC_OK)
+               return -EIO;
+
+       return count;
+}
+
+/**
+ * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ *
+ * This can store pdcs_size - 224 bytes of OS-Dependent data. We use a
+ * byte-by-byte write approach. It's up to userspace to deal with it when
+ * constructing its input buffer.
+ */
+static ssize_t
+pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count)
+{
+       unsigned long size;
+       unsigned short i;
+       u8 in[4];
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (!entry || !buf || !count)
+               return -EINVAL;
+
+       if (unlikely(pdcs_size <= 224))
+               return -ENOSYS;
+
+       if (unlikely(pdcs_osid != OS_ID_LINUX))
+               return -EPERM;
+
+       size = pdcs_size - 224;
+
+       if (count > size)
+               return -EMSGSIZE;
+
+       /* We'll use a local copy of buf */
+
+       for (i=0; i<count; i+=4) {
+               memset(in, 0, 4);
+               memcpy(in, buf+i, (count-i < 4) ? count-i : 4);
+               if (unlikely(pdc_stable_write(PDCS_ADDR_OSD2 + i, &in,
+                                       sizeof(in)) != PDC_OK))
+                       return -EIO;
+       }
+
+       return count;
+}
+
 /* The remaining attributes. */
 static PDCS_ATTR(size, 0444, pdcs_size_read, NULL);
 static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write);
 static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write);
 static PDCS_ATTR(timer, 0444, pdcs_timer_read, NULL);
-static PDCS_ATTR(osid, 0400, pdcs_osid_read, NULL);
+static PDCS_ATTR(osid, 0444, pdcs_osid_read, NULL);
+static PDCS_ATTR(osdep1, 0600, pdcs_osdep1_read, pdcs_osdep1_write);
+static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
 static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
+static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
 
 static struct subsys_attribute *pdcs_subsys_attrs[] = {
        &pdcs_attr_size,
@@ -784,7 +954,10 @@ static struct subsys_attribute *pdcs_subsys_attrs[] = {
        &pdcs_attr_autosearch,
        &pdcs_attr_timer,
        &pdcs_attr_osid,
+       &pdcs_attr_osdep1,
+       &pdcs_attr_diagnostic,
        &pdcs_attr_fastsize,
+       &pdcs_attr_osdep2,
        NULL,
 };
 
@@ -865,6 +1038,7 @@ pdc_stable_init(void)
 {
        struct subsys_attribute *attr;
        int i, rc = 0, error = 0;
+       u32 result;
 
        /* find the size of the stable storage */
        if (pdc_stable_get_size(&pdcs_size) != PDC_OK) 
@@ -876,6 +1050,13 @@ pdc_stable_init(void)
 
        printk(KERN_INFO PDCS_PREFIX " facility v%s\n", PDCS_VERSION);
 
+       /* get OSID */
+       if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
+               return -EIO;
+
+       /* the actual result is 16 bits away */
+       pdcs_osid = (u16)(result >> 16);
+
        /* For now we'll register the stable subsys within this driver */
        if ((rc = firmware_register(&stable_subsys)))
                goto fail_firmreg;
@@ -887,7 +1068,7 @@ pdc_stable_init(void)
        
        /* register the paths subsys as a subsystem of stable subsys */
        kset_set_kset_s(&paths_subsys, stable_subsys);
-       if ((rc= subsystem_register(&paths_subsys)))
+       if ((rc = subsystem_register(&paths_subsys)))
                goto fail_subsysreg;
 
        /* now we create all "files" for the paths subsys */
index 278f325021ee25d748d04e780b110355b806102a..d09e39e39c60cbbef178b3e39c6b3e0c1a7ab7c8 100644 (file)
@@ -316,10 +316,10 @@ static int reserve_sba_gart = 1;
 **
 ** Superdome (in particular, REO) allows only 64-bit CSR accesses.
 */
-#define READ_REG32(addr)        le32_to_cpu(__raw_readl(addr))
-#define READ_REG64(addr)        le64_to_cpu(__raw_readq(addr))
-#define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr)
-#define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr)
+#define READ_REG32(addr)       readl(addr)
+#define READ_REG64(addr)       readq(addr)
+#define WRITE_REG32(val, addr) writel((val), (addr))
+#define WRITE_REG64(val, addr) writeq((val), (addr))
 
 #ifdef CONFIG_64BIT
 #define READ_REG(addr)         READ_REG64(addr)
@@ -1427,7 +1427,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
        iov_order = get_order(iova_space_size >> (IOVP_SHIFT - PAGE_SHIFT));
        ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
 
-       DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits)\n",
+       DBG_INIT("%s() hpa 0x%p IOV %dMB (%d bits)\n",
                __FUNCTION__, ioc->ioc_hpa, iova_space_size >> 20,
                iov_order + PAGE_SHIFT);
 
@@ -1764,7 +1764,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
 
        sba_dev->num_ioc = num_ioc;
        for (i = 0; i < num_ioc; i++) {
-               unsigned long ioc_hpa = sba_dev->ioc[i].ioc_hpa;
+               void __iomem *ioc_hpa = sba_dev->ioc[i].ioc_hpa;
                unsigned int j;
 
                for (j=0; j < sizeof(u64) * ROPES_PER_IOC; j+=sizeof(u64)) {
@@ -1776,7 +1776,8 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
                         * Improves netperf UDP_STREAM by ~10% for bcm5701.
                         */
                        if (IS_PLUTO(sba_dev->iodc)) {
-                               unsigned long rope_cfg, cfg_val;
+                               void __iomem *rope_cfg;
+                               unsigned long cfg_val;
 
                                rope_cfg = ioc_hpa + IOC_ROPE0_CFG + j;
                                cfg_val = READ_REG(rope_cfg);
@@ -1902,7 +1903,7 @@ sba_common_init(struct sba_device *sba_dev)
         * (bit #61, big endian), we have to flush and sync every time
         * IO-PDIR is changed in Ike/Astro.
         */
-       if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) {
+       if (ioc_needs_fdc) {
                printk(KERN_INFO MODULE_NAME " FDC/SYNC required.\n");
        } else {
                printk(KERN_INFO MODULE_NAME " IOC has cache coherent PDIR.\n");
index 828eb45062de3fa51182d1c61660961307fc0b11..a988dc7a9abd33a4c7f579bcf15e7a3aab003dfe 100644 (file)
@@ -360,7 +360,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
 #endif
 
        for (i = 0; i < 16; i++) {
-               irq_desc[i].handler = &superio_interrupt_type;
+               irq_desc[i].chip = &superio_interrupt_type;
        }
 
        /*
index 7230926820234f3c676d50397abcdf41be4a7b52..5f7db9d2436e76141e15d50a44e9f1fc38e54378 100644 (file)
  */
 int
 pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
-       unsigned long size, unsigned long align, unsigned long min,
-       unsigned int type_mask,
-       void (*alignf)(void *, struct resource *,
-                       unsigned long, unsigned long),
-       void *alignf_data)
+               resource_size_t size, resource_size_t align,
+               resource_size_t min, unsigned int type_mask,
+               void (*alignf)(void *, struct resource *, resource_size_t,
+                               resource_size_t),
+               void *alignf_data)
 {
        int i, ret = -ENOMEM;
 
index f7cb00da38dfabbfd32e6c6ec366bf261f9ed7e4..1ec165df85223e4495ebb310b2702b70a1e14fd6 100644 (file)
@@ -95,8 +95,8 @@ static int zt5550_hc_config(struct pci_dev *pdev)
 
        hc_dev = pdev;
        dbg("hc_dev = %p", hc_dev);
-       dbg("pci resource start %lx", pci_resource_start(hc_dev, 1));
-       dbg("pci resource len %lx", pci_resource_len(hc_dev, 1));
+       dbg("pci resource start %llx", (unsigned long long)pci_resource_start(hc_dev, 1));
+       dbg("pci resource len %llx", (unsigned long long)pci_resource_len(hc_dev, 1));
 
        if(!request_mem_region(pci_resource_start(hc_dev, 1),
                                pci_resource_len(hc_dev, 1), MY_NAME)) {
@@ -108,8 +108,9 @@ static int zt5550_hc_config(struct pci_dev *pdev)
        hc_registers =
            ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1));
        if(!hc_registers) {
-               err("cannot remap MMIO region %lx @ %lx",
-                   pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1));
+               err("cannot remap MMIO region %llx @ %llx",
+                       (unsigned long long)pci_resource_len(hc_dev, 1),
+                       (unsigned long long)pci_resource_start(hc_dev, 1));
                ret = -ENODEV;
                goto exit_release_region;
        }
index 9bc1deb8df524225decdc7a5322d72ce2638f7bc..f8658d63f0773ca7022505bbe0aef995e4aaca12 100644 (file)
@@ -1089,8 +1089,8 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        
        dbg("pdev = %p\n", pdev);
-       dbg("pci resource start %lx\n", pci_resource_start(pdev, 0));
-       dbg("pci resource len %lx\n", pci_resource_len(pdev, 0));
+       dbg("pci resource start %llx\n", (unsigned long long)pci_resource_start(pdev, 0));
+       dbg("pci resource len %llx\n", (unsigned long long)pci_resource_len(pdev, 0));
 
        if (!request_mem_region(pci_resource_start(pdev, 0),
                                pci_resource_len(pdev, 0), MY_NAME)) {
@@ -1102,9 +1102,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0),
                                        pci_resource_len(pdev, 0));
        if (!ctrl->hpc_reg) {
-               err("cannot remap MMIO region %lx @ %lx\n",
-                               pci_resource_len(pdev, 0),
-                               pci_resource_start(pdev, 0));
+               err("cannot remap MMIO region %llx @ %llx\n",
+                   (unsigned long long)pci_resource_len(pdev, 0),
+                   (unsigned long long)pci_resource_start(pdev, 0));
                rc = -ENODEV;
                goto err_free_mem_region;
        }
index d77138ecb0981ec827a6d482d96f31eb6c5acc43..11f7858f0064f7a6ef992e7de171468e53806208 100644 (file)
@@ -1398,8 +1398,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 
        for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
                if (pci_resource_len(pdev, rc) > 0)
-                       dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc,
-                               pci_resource_start(pdev, rc), pci_resource_len(pdev, rc));
+                       dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
+                           (unsigned long long)pci_resource_start(pdev, rc),
+                           (unsigned long long)pci_resource_len(pdev, rc));
 
        info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, 
                pdev->subsystem_vendor, pdev->subsystem_device);
index f5cfbf2c047c92796c7bdde79d4dbc33c977c6a8..620e1139e607c763dfaa69ff25413c971de82310 100644 (file)
@@ -51,8 +51,10 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
                res = bus->resource[index];
                if (res && (res->flags & IORESOURCE_MEM) &&
                                !(res->flags & IORESOURCE_PREFETCH)) {
-                       out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
-                                       res->start, (res->end - res->start));
+                       out += sprintf(out, "start = %8.8llx, "
+                                       "length = %8.8llx\n",
+                                       (unsigned long long)res->start,
+                                       (unsigned long long)(res->end - res->start));
                }
        }
        out += sprintf(out, "Free resources: prefetchable memory\n");
@@ -60,16 +62,20 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
                res = bus->resource[index];
                if (res && (res->flags & IORESOURCE_MEM) &&
                               (res->flags & IORESOURCE_PREFETCH)) {
-                       out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
-                                       res->start, (res->end - res->start));
+                       out += sprintf(out, "start = %8.8llx, "
+                                       "length = %8.8llx\n",
+                                       (unsigned long long)res->start,
+                                       (unsigned long long)(res->end - res->start));
                }
        }
        out += sprintf(out, "Free resources: IO\n");
        for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
                res = bus->resource[index];
                if (res && (res->flags & IORESOURCE_IO)) {
-                       out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
-                                       res->start, (res->end - res->start));
+                       out += sprintf(out, "start = %8.8llx, "
+                                       "length = %8.8llx\n",
+                                       (unsigned long long)res->start,
+                                       (unsigned long long)(res->end - res->start));
                }
        }
        out += sprintf(out, "Free resources: bus numbers\n");
index 7f8429284fabe0663e4c6dc30fc6deefeaa178e3..76d023d8a33b92c7f940c05815434061f47a6adb 100644 (file)
@@ -429,12 +429,12 @@ static void irq_handler_init(int cap_id, int pos, int mask)
 
        spin_lock_irqsave(&irq_desc[pos].lock, flags);
        if (cap_id == PCI_CAP_ID_MSIX)
-               irq_desc[pos].handler = &msix_irq_type;
+               irq_desc[pos].chip = &msix_irq_type;
        else {
                if (!mask)
-                       irq_desc[pos].handler = &msi_irq_wo_maskbit_type;
+                       irq_desc[pos].chip = &msi_irq_wo_maskbit_type;
                else
-                       irq_desc[pos].handler = &msi_irq_w_maskbit_type;
+                       irq_desc[pos].chip = &msi_irq_w_maskbit_type;
        }
        spin_unlock_irqrestore(&irq_desc[pos].lock, flags);
 }
index bc405c035ce34b4ae00d54a61286782e31416125..606f9b6f70ebe220617aa437982c4f5287046d40 100644 (file)
@@ -87,7 +87,7 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf)
        char * str = buf;
        int i;
        int max = 7;
-       u64 start, end;
+       resource_size_t start, end;
 
        if (pci_dev->subordinate)
                max = DEVICE_COUNT_RESOURCE;
@@ -365,7 +365,7 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
                                                       struct device, kobj));
        struct resource *res = (struct resource *)attr->private;
        enum pci_mmap_state mmap_type;
-       u64 start, end;
+       resource_size_t start, end;
        int i;
 
        for (i = 0; i < PCI_ROM_RESOURCE; i++)
index 23d3b17c8cad2cacacb32bd042aefa2c532eb848..cf57d7de3765fcceb37216501c0ace480cc95fa2 100644 (file)
@@ -691,10 +691,12 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
        return 0;
 
 err_out:
-       printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
+       printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%llx@%llx "
+               "for device %s\n",
                pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
                bar + 1, /* PCI BAR # */
-               pci_resource_len(pdev, bar), pci_resource_start(pdev, bar),
+               (unsigned long long)pci_resource_len(pdev, bar),
+               (unsigned long long)pci_resource_start(pdev, bar),
                pci_name(pdev));
        return -EBUSY;
 }
index 29bdeca031a8b49c60c7de124eabc68022c3c3b2..9cc842b666eb1d1d43fc24f9b06b2a3dd3a2f491 100644 (file)
@@ -6,10 +6,10 @@ extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_cleanup_rom(struct pci_dev *dev);
 extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
-                                 unsigned long size, unsigned long align,
-                                 unsigned long min, unsigned int type_mask,
+                                 resource_size_t size, resource_size_t align,
+                                 resource_size_t min, unsigned int type_mask,
                                  void (*alignf)(void *, struct resource *,
-                                                unsigned long, unsigned long),
+                                             resource_size_t, resource_size_t),
                                  void *alignf_data);
 /* Firmware callbacks */
 extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
index 54b2ebc9c91a4b4e18dead4f363b0c9c5150d2a5..99cf33379769310619557605b72c390bc913b39f 100644 (file)
@@ -302,12 +302,6 @@ static struct file_operations proc_bus_pci_operations = {
 #endif /* HAVE_PCI_MMAP */
 };
 
-#if BITS_PER_LONG == 32
-#define LONG_FORMAT "\t%08lx"
-#else
-#define LONG_FORMAT "\t%16lx"
-#endif
-
 /* iterator */
 static void *pci_seq_start(struct seq_file *m, loff_t *pos)
 {
@@ -356,18 +350,18 @@ static int show_device(struct seq_file *m, void *v)
                        dev->irq);
        /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */
        for (i=0; i<7; i++) {
-               u64 start, end;
+               resource_size_t start, end;
                pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
-               seq_printf(m, LONG_FORMAT,
-                       ((unsigned long)start) |
-                       (dev->resource[i].flags & PCI_REGION_FLAG_MASK));
+               seq_printf(m, "\t%16llx",
+                       (unsigned long long)(start |
+                       (dev->resource[i].flags & PCI_REGION_FLAG_MASK)));
        }
        for (i=0; i<7; i++) {
-               u64 start, end;
+               resource_size_t start, end;
                pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
-               seq_printf(m, LONG_FORMAT,
+               seq_printf(m, "\t%16llx",
                        dev->resource[i].start < dev->resource[i].end ?
-                       (unsigned long)(end - start) + 1 : 0);
+                       (unsigned long long)(end - start) + 1 : 0);
        }
        seq_putc(m, '\t');
        if (drv)
index 598a115cd00e762abb868b76e16447fa11faa0a3..cbb69cf41311a947f96fd3231f1d00b070d98082 100644 (file)
@@ -80,8 +80,8 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
        } 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);
+                       return (void __iomem *)(unsigned long)
+                               pci_resource_start(pdev, PCI_ROM_RESOURCE);
                } else {
                        /* assign the ROM an address if it doesn't have one */
                        if (res->parent == NULL &&
@@ -170,11 +170,11 @@ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
                return rom;
 
        res->end = res->start + *size;
-       memcpy_fromio((void*)res->start, rom, *size);
+       memcpy_fromio((void*)(unsigned long)res->start, rom, *size);
        pci_unmap_rom(pdev, rom);
        res->flags |= IORESOURCE_ROM_COPY;
 
-       return (void __iomem *)res->start;
+       return (void __iomem *)(unsigned long)res->start;
 }
 
 /**
@@ -227,7 +227,7 @@ 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);
+               kfree((void*)(unsigned long)res->start);
                res->flags &= ~IORESOURCE_ROM_COPY;
                res->start = 0;
                res->end = 0;
index 35086e80faa91a9db5ea225b5166d29f1b88e1b4..47c1071ad84ea06b057faac42e6ea60aeb87c5fe 100644 (file)
@@ -357,8 +357,10 @@ pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
                        order = __ffs(align) - 20;
                        if (order > 11) {
                                printk(KERN_WARNING "PCI: region %s/%d "
-                                      "too large: %lx-%lx\n",
-                                      pci_name(dev), i, r->start, r->end);
+                                      "too large: %llx-%llx\n",
+                                       pci_name(dev), i,
+                                       (unsigned long long)r->start,
+                                       (unsigned long long)r->end);
                                r->flags = 0;
                                continue;
                        }
index 577f4b55c46d6e37f52b5f67654ac94ecf73b0ab..ab78e4bbdd83044bc6bb6a3f32e4d7ea3834bf52 100644 (file)
@@ -40,8 +40,9 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
 
        pcibios_resource_to_bus(dev, &region, res);
 
-       pr_debug("  got res [%lx:%lx] bus [%lx:%lx] flags %lx for "
-                "BAR %d of %s\n", res->start, res->end,
+       pr_debug("  got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
+                "BAR %d of %s\n", (unsigned long long)res->start,
+                (unsigned long long)res->end,
                 region.start, region.end, res->flags, resno, pci_name(dev));
 
        new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
@@ -104,10 +105,12 @@ pci_claim_resource(struct pci_dev *dev, int resource)
                err = insert_resource(root, res);
 
        if (err) {
-               printk(KERN_ERR "PCI: %s region %d of %s %s [%lx:%lx]\n",
-                      root ? "Address space collision on" :
-                             "No parent found for",
-                      resource, dtype, pci_name(dev), res->start, res->end);
+               printk(KERN_ERR "PCI: %s region %d of %s %s [%llx:%llx]\n",
+                       root ? "Address space collision on" :
+                               "No parent found for",
+                       resource, dtype, pci_name(dev),
+                       (unsigned long long)res->start,
+                       (unsigned long long)res->end);
        }
 
        return err;
@@ -118,7 +121,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
 {
        struct pci_bus *bus = dev->bus;
        struct resource *res = dev->resource + resno;
-       unsigned long size, min, align;
+       resource_size_t size, min, align;
        int ret;
 
        size = res->end - res->start + 1;
@@ -145,9 +148,11 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
        }
 
        if (ret) {
-               printk(KERN_ERR "PCI: Failed to allocate %s resource #%d:%lx@%lx for %s\n",
-                      res->flags & IORESOURCE_IO ? "I/O" : "mem",
-                      resno, size, res->start, pci_name(dev));
+               printk(KERN_ERR "PCI: Failed to allocate %s resource "
+                       "#%d:%llx@%llx for %s\n",
+                       res->flags & IORESOURCE_IO ? "I/O" : "mem",
+                       resno, (unsigned long long)size,
+                       (unsigned long long)res->start, pci_name(dev));
        } else if (resno < PCI_BRIDGE_RESOURCES) {
                pci_update_resource(dev, res, resno);
        }
@@ -204,7 +209,7 @@ pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
                struct resource *r;
                struct resource_list *list, *tmp;
-               unsigned long r_align;
+               resource_size_t r_align;
 
                r = &dev->resource[i];
                r_align = r->end - r->start;
@@ -213,13 +218,14 @@ pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
                        continue;
                if (!r_align) {
                        printk(KERN_WARNING "PCI: Ignore bogus resource %d "
-                                           "[%lx:%lx] of %s\n",
-                                           i, r->start, r->end, pci_name(dev));
+                               "[%llx:%llx] of %s\n",
+                               i, (unsigned long long)r->start,
+                               (unsigned long long)r->end, pci_name(dev));
                        continue;
                }
                r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
                for (list = head; ; list = list->next) {
-                       unsigned long align = 0;
+                       resource_size_t align = 0;
                        struct resource_list *ln = list->next;
                        int idx;
 
index b39435bbfaeb2aa3c3f14bbc34499f6a16046313..c662e4f89d46174cf54b2d8af74c8d63b23fcc10 100644 (file)
@@ -244,8 +244,8 @@ static void hs_map_irq(hs_socket_t *sp, unsigned int irq)
 
        hs_mapped_irq[irq].sock = sp;
        /* insert ourselves as the irq controller */
-       hs_mapped_irq[irq].old_handler = irq_desc[irq].handler;
-       irq_desc[irq].handler = &hd64465_ss_irq_type;
+       hs_mapped_irq[irq].old_handler = irq_desc[irq].chip;
+       irq_desc[irq].chip = &hd64465_ss_irq_type;
 }
 
 
@@ -260,7 +260,7 @@ static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq)
            return;
                
        /* restore the original irq controller */
-       irq_desc[irq].handler = hs_mapped_irq[irq].old_handler;
+       irq_desc[irq].chip = hs_mapped_irq[irq].old_handler;
 }
 
 /*============================================================*/
index a2f05f48515654e25d1284a260a6c52a522917f3..ff51a65d9433af984b04ce8cf2fe88812f023796 100644 (file)
@@ -1084,9 +1084,10 @@ static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
     u_short base, i;
     u_char map;
     
-    debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#lx-%#lx, "
+    debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, "
          "%#x)\n", sock, mem->map, mem->flags, mem->speed,
-         mem->res->start, mem->res->end, mem->card_start);
+         (unsigned long long)mem->res->start,
+         (unsigned long long)mem->res->end, mem->card_start);
 
     map = mem->map;
     if ((map > 4) || (mem->card_start > 0x3ffffff) ||
index 0e07d9535116db884fcbe1762d0971ae3192669b..d0f68ab8f04119c12661a27e1785d76b6a372be4 100644 (file)
@@ -157,7 +157,7 @@ MODULE_LICENSE("Dual MPL/GPL");
 
 static int pcmcia_schlvl = PCMCIA_SCHLVL;
 
-static spinlock_t events_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(events_lock);
 
 
 #define PCMCIA_SOCKET_KEY_5V 1
@@ -644,7 +644,7 @@ static struct platform_device m8xx_device = {
 };
 
 static u32 pending_events[PCMCIA_SOCKETS_NO];
-static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(pending_event_lock);
 
 static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
index 247ab837f841739f0982c51ecd937692d841f5ef..9ee26c1b863566a0d846e4033a424aa3b8f9f68d 100644 (file)
@@ -642,7 +642,8 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
                goto err_out_free_mem;
 
        printk(KERN_INFO "pd6729: Cirrus PD6729 PCI to PCMCIA Bridge "
-               "at 0x%lx on irq %d\n", pci_resource_start(dev, 0), dev->irq);
+               "at 0x%llx on irq %d\n",
+               (unsigned long long)pci_resource_start(dev, 0), dev->irq);
        /*
         * Since we have no memory BARs some firmware may not
         * have had PCI_COMMAND_MEMORY enabled, yet the device needs it.
index 0f8b157c97177d30c3dc2389a70dd85a211c5b75..c3176b16b7bea5223aba2031251196cd88440533 100644 (file)
@@ -72,7 +72,7 @@ static DEFINE_MUTEX(rsrc_mutex);
 ======================================================================*/
 
 static struct resource *
-make_resource(unsigned long b, unsigned long n, int flags, char *name)
+make_resource(resource_size_t b, resource_size_t n, int flags, char *name)
 {
        struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
@@ -86,8 +86,8 @@ make_resource(unsigned long b, unsigned long n, int flags, char *name)
 }
 
 static struct resource *
-claim_region(struct pcmcia_socket *s, unsigned long base, unsigned long size,
-            int type, char *name)
+claim_region(struct pcmcia_socket *s, resource_size_t base,
+               resource_size_t size, int type, char *name)
 {
        struct resource *res, *parent;
 
@@ -519,10 +519,10 @@ struct pcmcia_align_data {
 
 static void
 pcmcia_common_align(void *align_data, struct resource *res,
-                   unsigned long size, unsigned long align)
+                       resource_size_t size, resource_size_t align)
 {
        struct pcmcia_align_data *data = align_data;
-       unsigned long start;
+       resource_size_t start;
        /*
         * Ensure that we have the correct start address
         */
@@ -533,8 +533,8 @@ pcmcia_common_align(void *align_data, struct resource *res,
 }
 
 static void
-pcmcia_align(void *align_data, struct resource *res,
-            unsigned long size, unsigned long align)
+pcmcia_align(void *align_data, struct resource *res, resource_size_t size,
+               resource_size_t align)
 {
        struct pcmcia_align_data *data = align_data;
        struct resource_map *m;
@@ -808,8 +808,10 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
                if (res->flags & IORESOURCE_IO) {
                        if (res == &ioport_resource)
                                continue;
-                       printk(KERN_INFO "pcmcia: parent PCI bridge I/O window: 0x%lx - 0x%lx\n",
-                              res->start, res->end);
+                       printk(KERN_INFO "pcmcia: parent PCI bridge I/O "
+                               "window: 0x%llx - 0x%llx\n",
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end);
                        if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
                                done |= IORESOURCE_IO;
 
@@ -818,8 +820,10 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
                if (res->flags & IORESOURCE_MEM) {
                        if (res == &iomem_resource)
                                continue;
-                       printk(KERN_INFO "pcmcia: parent PCI bridge Memory window: 0x%lx - 0x%lx\n",
-                              res->start, res->end);
+                       printk(KERN_INFO "pcmcia: parent PCI bridge Memory "
+                               "window: 0x%llx - 0x%llx\n",
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end);
                        if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
                                done |= IORESOURCE_MEM;
                }
index 73bad1d5cb23d8660b803f9933a026dd36ad530a..65a60671659f1e1c77861a2235e5d31bbcc1035b 100644 (file)
@@ -756,8 +756,9 @@ static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
     u_long base, len, mmap;
 
     debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, "
-         "%#lx-%#lx, %#x)\n", psock, mem->map, mem->flags,
-         mem->speed, mem->res->start, mem->res->end, mem->card_start);
+         "%#llx-%#llx, %#x)\n", psock, mem->map, mem->flags,
+         mem->speed, (unsigned long long)mem->res->start,
+         (unsigned long long)mem->res->end, mem->card_start);
     if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
        (mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) ||
        (mem->res->start > mem->res->end) || (mem->speed > 1000))
index a2d8ce7fef9c97bb0149b4e6166e044820119ea2..3163e3d73da13c1d6f58beecd6271a36f1bcb2e1 100644 (file)
@@ -264,7 +264,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
                        if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
                                pnp_printf(buffer," disabled\n");
                        else
-                               pnp_printf(buffer," 0x%lx-0x%lx\n",
+                               pnp_printf(buffer," 0x%llx-0x%llx\n",
                                                pnp_port_start(dev, i),
                                                pnp_port_end(dev, i));
                }
@@ -275,7 +275,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
                        if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
                                pnp_printf(buffer," disabled\n");
                        else
-                               pnp_printf(buffer," 0x%lx-0x%lx\n",
+                               pnp_printf(buffer," 0x%llx-0x%llx\n",
                                                pnp_mem_start(dev, i),
                                                pnp_mem_end(dev, i));
                }
@@ -286,7 +286,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
                        if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
                                pnp_printf(buffer," disabled\n");
                        else
-                               pnp_printf(buffer," %ld\n",
+                               pnp_printf(buffer," %lld\n",
                                                pnp_irq(dev, i));
                }
        }
@@ -296,7 +296,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
                        if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
                                pnp_printf(buffer," disabled\n");
                        else
-                               pnp_printf(buffer," %ld\n",
+                               pnp_printf(buffer," %lld\n",
                                                pnp_dma(dev, i));
                }
        }
index 6fff109bdab606e98eb188f70a4b4a1dcafe6415..1d7a5b87f4cbc3157e7abbf86d11da638f748eeb 100644 (file)
@@ -20,7 +20,8 @@ DECLARE_MUTEX(pnp_res_mutex);
 
 static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
 {
-       unsigned long *start, *end, *flags;
+       resource_size_t *start, *end;
+       unsigned long *flags;
 
        if (!dev || !rule)
                return -EINVAL;
@@ -63,7 +64,8 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
 
 static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
 {
-       unsigned long *start, *end, *flags;
+       resource_size_t *start, *end;
+       unsigned long *flags;
 
        if (!dev || !rule)
                return -EINVAL;
@@ -116,7 +118,8 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
 
 static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
 {
-       unsigned long *start, *end, *flags;
+       resource_size_t *start, *end;
+       unsigned long *flags;
        int i;
 
        /* IRQ priority: this table is good for i386 */
@@ -168,7 +171,8 @@ static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
 
 static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
 {
-       unsigned long *start, *end, *flags;
+       resource_size_t *start, *end;
+       unsigned long *flags;
        int i;
 
        /* DMA priority: this table is good for i386 */
@@ -582,7 +586,8 @@ int pnp_disable_dev(struct pnp_dev *dev)
  * @size: size of region
  *
  */
-void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size)
+void pnp_resource_change(struct resource *resource, resource_size_t start,
+                               resource_size_t size)
 {
        if (resource == NULL)
                return;
index 6ded527169f4b805b43a77dba11a5c0b23d42af8..7bb892f58cc09815da0ee5963417cbc312bf0f9b 100644 (file)
@@ -241,7 +241,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
 {
        int tmp;
        struct pnp_dev *tdev;
-       unsigned long *port, *end, *tport, *tend;
+       resource_size_t *port, *end, *tport, *tend;
        port = &dev->res.port_resource[idx].start;
        end = &dev->res.port_resource[idx].end;
 
@@ -297,7 +297,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
 {
        int tmp;
        struct pnp_dev *tdev;
-       unsigned long *addr, *end, *taddr, *tend;
+       resource_size_t *addr, *end, *taddr, *tend;
        addr = &dev->res.mem_resource[idx].start;
        end = &dev->res.mem_resource[idx].end;
 
@@ -358,7 +358,7 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
 {
        int tmp;
        struct pnp_dev *tdev;
-       unsigned long * irq = &dev->res.irq_resource[idx].start;
+       resource_size_t * irq = &dev->res.irq_resource[idx].start;
 
        /* if the resource doesn't exist, don't complain about it */
        if (cannot_compare(dev->res.irq_resource[idx].flags))
@@ -423,7 +423,7 @@ 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;
+       resource_size_t * dma = &dev->res.dma_resource[idx].start;
 
        /* if the resource doesn't exist, don't complain about it */
        if (cannot_compare(dev->res.dma_resource[idx].flags))
index b9fab2ae3a36108ed2bbc48499682382c8e3b88f..8b56bbdd011ec0d5bf9870ca36abeda25caff49e 100644 (file)
@@ -17,8 +17,8 @@
  * These interrupt-safe spinlocks protect all accesses to RIO
  * configuration space and doorbell access.
  */
-static spinlock_t rio_config_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t rio_doorbell_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(rio_config_lock);
+static DEFINE_SPINLOCK(rio_doorbell_lock);
 
 /*
  *  Wrappers for all RIO configuration access functions.  They just check
index bccff400b198d6e0da250fd483a551ad60d992bd..f2fc81a9074d8af26c79940f87ddaa8c98712999 100644 (file)
@@ -162,6 +162,16 @@ config RTC_DRV_PCF8583
          This driver can also be built as a module. If so, the module
          will be called rtc-pcf8583.
 
+config RTC_DRV_RS5C348
+       tristate "Ricoh RS5C348A/B"
+       depends on RTC_CLASS && SPI
+       help
+         If you say yes here you get support for the
+         Ricoh RS5C348A and RS5C348B RTC chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-rs5c348.
+
 config RTC_DRV_RS5C372
        tristate "Ricoh RS5C372A/B"
        depends on RTC_CLASS && I2C
index 900d210dd1a24e017b46801251b5bdcea46e4407..da5e38774e130f444f1eb43f31740f5bae404abe 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_RTC_DRV_DS1742)  += rtc-ds1742.o
 obj-$(CONFIG_RTC_DRV_PCF8563)  += rtc-pcf8563.o
 obj-$(CONFIG_RTC_DRV_PCF8583)  += rtc-pcf8583.o
 obj-$(CONFIG_RTC_DRV_RS5C372)  += rtc-rs5c372.o
+obj-$(CONFIG_RTC_DRV_RS5C348)  += rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_M48T86)   += rtc-m48t86.o
 obj-$(CONFIG_RTC_DRV_DS1553)   += rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_EP93XX)   += rtc-ep93xx.o
index 5396beec30d0ca62b3d97a0c73c0ac66cb8ceccc..1cb61a761cb284cc6dd590e6ebd8062f6271d246 100644 (file)
@@ -94,7 +94,9 @@ exit_kfree:
        kfree(rtc);
 
 exit_idr:
+       mutex_lock(&idr_lock);
        idr_remove(&rtc_idr, id);
+       mutex_unlock(&idr_lock);
 
 exit:
        dev_err(dev, "rtc core: unable to register %s, err = %d\n",
index ecafbad41a242ce894d9247c88c6e1a5d0e67734..762521a1419cf296f080e7e4672e430f3029decc 100644 (file)
@@ -226,7 +226,7 @@ static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd,
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
        if (pdata->irq < 0)
-               return -ENOIOCTLCMD;
+               return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
        switch (cmd) {
        case RTC_AIE_OFF:
                pdata->irqen &= ~RTC_AF;
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
new file mode 100644 (file)
index 0000000..0964d1d
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * A SPI driver for the Ricoh RS5C348 RTC
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The board specific init code should provide characteristics of this
+ * device:
+ *     Mode 1 (High-Active, Shift-Then-Sample), High Avtive CS
+ */
+
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/rtc.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+
+#define DRV_VERSION "0.1"
+
+#define RS5C348_REG_SECS       0
+#define RS5C348_REG_MINS       1
+#define RS5C348_REG_HOURS      2
+#define RS5C348_REG_WDAY       3
+#define RS5C348_REG_DAY        4
+#define RS5C348_REG_MONTH      5
+#define RS5C348_REG_YEAR       6
+#define RS5C348_REG_CTL1       14
+#define RS5C348_REG_CTL2       15
+
+#define RS5C348_SECS_MASK      0x7f
+#define RS5C348_MINS_MASK      0x7f
+#define RS5C348_HOURS_MASK     0x3f
+#define RS5C348_WDAY_MASK      0x03
+#define RS5C348_DAY_MASK       0x3f
+#define RS5C348_MONTH_MASK     0x1f
+
+#define RS5C348_BIT_PM 0x20    /* REG_HOURS */
+#define RS5C348_BIT_Y2K        0x80    /* REG_MONTH */
+#define RS5C348_BIT_24H        0x20    /* REG_CTL1 */
+#define RS5C348_BIT_XSTP       0x10    /* REG_CTL2 */
+#define RS5C348_BIT_VDET       0x40    /* REG_CTL2 */
+
+#define RS5C348_CMD_W(addr)    (((addr) << 4) | 0x08)  /* single write */
+#define RS5C348_CMD_R(addr)    (((addr) << 4) | 0x0c)  /* single read */
+#define RS5C348_CMD_MW(addr)   (((addr) << 4) | 0x00)  /* burst write */
+#define RS5C348_CMD_MR(addr)   (((addr) << 4) | 0x04)  /* burst read */
+
+struct rs5c348_plat_data {
+       struct rtc_device *rtc;
+       int rtc_24h;
+};
+
+static int
+rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct rs5c348_plat_data *pdata = spi->dev.platform_data;
+       u8 txbuf[5+7], *txp;
+       int ret;
+
+       /* Transfer 5 bytes before writing SEC.  This gives 31us for carry. */
+       txp = txbuf;
+       txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+       txbuf[1] = 0;   /* dummy */
+       txbuf[2] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+       txbuf[3] = 0;   /* dummy */
+       txbuf[4] = RS5C348_CMD_MW(RS5C348_REG_SECS); /* cmd, sec, ... */
+       txp = &txbuf[5];
+       txp[RS5C348_REG_SECS] = BIN2BCD(tm->tm_sec);
+       txp[RS5C348_REG_MINS] = BIN2BCD(tm->tm_min);
+       if (pdata->rtc_24h) {
+               txp[RS5C348_REG_HOURS] = BIN2BCD(tm->tm_hour);
+       } else {
+               /* hour 0 is AM12, noon is PM12 */
+               txp[RS5C348_REG_HOURS] = BIN2BCD((tm->tm_hour + 11) % 12 + 1) |
+                       (tm->tm_hour >= 12 ? RS5C348_BIT_PM : 0);
+       }
+       txp[RS5C348_REG_WDAY] = BIN2BCD(tm->tm_wday);
+       txp[RS5C348_REG_DAY] = BIN2BCD(tm->tm_mday);
+       txp[RS5C348_REG_MONTH] = BIN2BCD(tm->tm_mon + 1) |
+               (tm->tm_year >= 100 ? RS5C348_BIT_Y2K : 0);
+       txp[RS5C348_REG_YEAR] = BIN2BCD(tm->tm_year % 100);
+       /* write in one transfer to avoid data inconsistency */
+       ret = spi_write_then_read(spi, txbuf, sizeof(txbuf), NULL, 0);
+       udelay(62);     /* Tcsr 62us */
+       return ret;
+}
+
+static int
+rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct rs5c348_plat_data *pdata = spi->dev.platform_data;
+       u8 txbuf[5], rxbuf[7];
+       int ret;
+
+       /* Transfer 5 byte befores reading SEC.  This gives 31us for carry. */
+       txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+       txbuf[1] = 0;   /* dummy */
+       txbuf[2] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+       txbuf[3] = 0;   /* dummy */
+       txbuf[4] = RS5C348_CMD_MR(RS5C348_REG_SECS); /* cmd, sec, ... */
+
+       /* read in one transfer to avoid data inconsistency */
+       ret = spi_write_then_read(spi, txbuf, sizeof(txbuf),
+                                 rxbuf, sizeof(rxbuf));
+       udelay(62);     /* Tcsr 62us */
+       if (ret < 0)
+               return ret;
+
+       tm->tm_sec = BCD2BIN(rxbuf[RS5C348_REG_SECS] & RS5C348_SECS_MASK);
+       tm->tm_min = BCD2BIN(rxbuf[RS5C348_REG_MINS] & RS5C348_MINS_MASK);
+       tm->tm_hour = BCD2BIN(rxbuf[RS5C348_REG_HOURS] & RS5C348_HOURS_MASK);
+       if (!pdata->rtc_24h) {
+               tm->tm_hour %= 12;
+               if (rxbuf[RS5C348_REG_HOURS] & RS5C348_BIT_PM)
+                       tm->tm_hour += 12;
+       }
+       tm->tm_wday = BCD2BIN(rxbuf[RS5C348_REG_WDAY] & RS5C348_WDAY_MASK);
+       tm->tm_mday = BCD2BIN(rxbuf[RS5C348_REG_DAY] & RS5C348_DAY_MASK);
+       tm->tm_mon =
+               BCD2BIN(rxbuf[RS5C348_REG_MONTH] & RS5C348_MONTH_MASK) - 1;
+       /* year is 1900 + tm->tm_year */
+       tm->tm_year = BCD2BIN(rxbuf[RS5C348_REG_YEAR]) +
+               ((rxbuf[RS5C348_REG_MONTH] & RS5C348_BIT_Y2K) ? 100 : 0);
+
+       if (rtc_valid_tm(tm) < 0) {
+               dev_err(&spi->dev, "retrieved date/time is not valid.\n");
+               rtc_time_to_tm(0, tm);
+       }
+
+       return 0;
+}
+
+static struct rtc_class_ops rs5c348_rtc_ops = {
+       .read_time      = rs5c348_rtc_read_time,
+       .set_time       = rs5c348_rtc_set_time,
+};
+
+static struct spi_driver rs5c348_driver;
+
+static int __devinit rs5c348_probe(struct spi_device *spi)
+{
+       int ret;
+       struct rtc_device *rtc;
+       struct rs5c348_plat_data *pdata;
+
+       pdata = kzalloc(sizeof(struct rs5c348_plat_data), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+       spi->dev.platform_data = pdata;
+
+       /* Check D7 of SECOND register */
+       ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_SECS));
+       if (ret < 0 || (ret & 0x80)) {
+               dev_err(&spi->dev, "not found.\n");
+               goto kfree_exit;
+       }
+
+       dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n");
+       dev_info(&spi->dev, "spiclk %u KHz.\n",
+                (spi->max_speed_hz + 500) / 1000);
+
+       /* turn RTC on if it was not on */
+       ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
+       if (ret < 0)
+               goto kfree_exit;
+       if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) {
+               u8 buf[2];
+               if (ret & RS5C348_BIT_VDET)
+                       dev_warn(&spi->dev, "voltage-low detected.\n");
+               buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
+               buf[1] = 0;
+               ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
+               if (ret < 0)
+                       goto kfree_exit;
+       }
+
+       ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL1));
+       if (ret < 0)
+               goto kfree_exit;
+       if (ret & RS5C348_BIT_24H)
+               pdata->rtc_24h = 1;
+
+       rtc = rtc_device_register(rs5c348_driver.driver.name, &spi->dev,
+                                 &rs5c348_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto kfree_exit;
+       }
+
+       pdata->rtc = rtc;
+
+       return 0;
+ kfree_exit:
+       kfree(pdata);
+       return ret;
+}
+
+static int __devexit rs5c348_remove(struct spi_device *spi)
+{
+       struct rs5c348_plat_data *pdata = spi->dev.platform_data;
+       struct rtc_device *rtc = pdata->rtc;
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+       kfree(pdata);
+       return 0;
+}
+
+static struct spi_driver rs5c348_driver = {
+       .driver = {
+               .name   = "rs5c348",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = rs5c348_probe,
+       .remove = __devexit_p(rs5c348_remove),
+};
+
+static __init int rs5c348_init(void)
+{
+       return spi_register_driver(&rs5c348_driver);
+}
+
+static __exit void rs5c348_exit(void)
+{
+       spi_unregister_driver(&rs5c348_driver);
+}
+
+module_init(rs5c348_init);
+module_exit(rs5c348_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
index ab486fbc828dab567357ab1d1ca04e2c5fc7d625..9cd1cb304bb2a7b66a4a5aab5442e472419961df 100644 (file)
@@ -45,7 +45,7 @@
 
 static unsigned long rtc_freq = 1024;
 static struct rtc_time rtc_alarm;
-static spinlock_t sa1100_rtc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(sa1100_rtc_lock);
 
 static int rtc_update_alarm(struct rtc_time *alrm)
 {
index 33e029207e261cd2ce20f0bcb75375fa8380a768..4b9291dd444354ab1f2f374c26d2d0069266b800 100644 (file)
@@ -93,7 +93,7 @@ static void __iomem *rtc2_base;
 
 static unsigned long epoch = 1970;     /* Jan 1 1970 00:00:00 */
 
-static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(rtc_lock);
 static char rtc_name[] = "RTC";
 static unsigned long periodic_frequency;
 static unsigned long periodic_count;
index cfb1fff3787caafd63fe05a2c36587bfdb8f19a5..2dc179b14ce6484e5dd6f53a8221461d0854857f 100644 (file)
@@ -95,7 +95,7 @@ dasd_alloc_device(void)
        spin_lock_init(&device->mem_lock);
        spin_lock_init(&device->request_queue_lock);
        atomic_set (&device->tasklet_scheduled, 0);
-       tasklet_init(&device->tasklet, 
+       tasklet_init(&device->tasklet,
                     (void (*)(unsigned long)) dasd_tasklet,
                     (unsigned long) device);
        INIT_LIST_HEAD(&device->ccw_queue);
@@ -128,7 +128,7 @@ dasd_state_new_to_known(struct dasd_device *device)
        int rc;
 
        /*
-        * As long as the device is not in state DASD_STATE_NEW we want to 
+        * As long as the device is not in state DASD_STATE_NEW we want to
         * keep the reference count > 0.
         */
        dasd_get_device(device);
@@ -336,7 +336,7 @@ dasd_decrease_state(struct dasd_device *device)
        if (device->state == DASD_STATE_ONLINE &&
            device->target <= DASD_STATE_READY)
                dasd_state_online_to_ready(device);
-       
+
        if (device->state == DASD_STATE_READY &&
            device->target <= DASD_STATE_BASIC)
                dasd_state_ready_to_basic(device);
@@ -348,7 +348,7 @@ dasd_decrease_state(struct dasd_device *device)
        if (device->state == DASD_STATE_BASIC &&
            device->target <= DASD_STATE_KNOWN)
                dasd_state_basic_to_known(device);
-       
+
        if (device->state == DASD_STATE_KNOWN &&
            device->target <= DASD_STATE_NEW)
                dasd_state_known_to_new(device);
@@ -994,7 +994,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                      ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
 
        /* Find out the appropriate era_action. */
-       if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) 
+       if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
                era = dasd_era_fatal;
        else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
                 irb->scsw.cstat == 0 &&
@@ -1004,7 +1004,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                era = dasd_era_fatal; /* don't recover this request */
        else if (irb->esw.esw0.erw.cons)
                era = device->discipline->examine_error(cqr, irb);
-       else 
+       else
                era = dasd_era_recover;
 
        DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);
@@ -1287,7 +1287,7 @@ __dasd_start_head(struct dasd_device * device)
 }
 
 /*
- * Remove requests from the ccw queue. 
+ * Remove requests from the ccw queue.
  */
 static void
 dasd_flush_ccw_queue(struct dasd_device * device, int all)
@@ -1450,23 +1450,23 @@ dasd_sleep_on(struct dasd_ccw_req * cqr)
        wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
-       
+
        device = cqr->device;
        spin_lock_irq(get_ccwdev_lock(device->cdev));
-       
+
        init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
        cqr->callback_data = (void *) &wait_q;
        cqr->status = DASD_CQR_QUEUED;
        list_add_tail(&cqr->list, &device->ccw_queue);
-       
+
        /* let the bh start the request to keep them in order */
        dasd_schedule_bh(device);
-       
+
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
        wait_event(wait_q, _wait_for_wakeup(cqr));
-       
+
        /* Request status is either done or failed. */
        rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
        return rc;
@@ -1568,7 +1568,7 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
        wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
-       
+
        device = cqr->device;
        spin_lock_irq(get_ccwdev_lock(device->cdev));
        rc = _dasd_term_running_cqr(device);
@@ -1576,20 +1576,20 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
                spin_unlock_irq(get_ccwdev_lock(device->cdev));
                return rc;
        }
-       
+
        init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
        cqr->callback_data = (void *) &wait_q;
        cqr->status = DASD_CQR_QUEUED;
        list_add(&cqr->list, &device->ccw_queue);
-       
+
        /* let the bh start the request to keep them in order */
        dasd_schedule_bh(device);
-       
+
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
        wait_event(wait_q, _wait_for_wakeup(cqr));
-       
+
        /* Request status is either done or failed. */
        rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
        return rc;
@@ -1725,7 +1725,7 @@ dasd_flush_request_queue(struct dasd_device * device)
 
        if (!device->request_queue)
                return;
-       
+
        spin_lock_irq(&device->request_queue_lock);
        while (!list_empty(&device->request_queue->queue_head)) {
                req = elv_next_request(device->request_queue);
@@ -1834,7 +1834,6 @@ dasd_exit(void)
        }
        dasd_gendisk_exit();
        dasd_devmap_exit();
-       devfs_remove("dasd");
        if (dasd_debug_area != NULL) {
                debug_unregister(dasd_debug_area);
                dasd_debug_area = NULL;
@@ -1855,15 +1854,34 @@ dasd_generic_probe (struct ccw_device *cdev,
 {
        int ret;
 
+       ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
+       if (ret) {
+               printk(KERN_WARNING
+                      "dasd_generic_probe: could not set ccw-device options "
+                      "for %s\n", cdev->dev.bus_id);
+               return ret;
+       }
        ret = dasd_add_sysfs_files(cdev);
        if (ret) {
                printk(KERN_WARNING
                       "dasd_generic_probe: could not add sysfs entries "
                       "for %s\n", cdev->dev.bus_id);
-       } else {
-               cdev->handler = &dasd_int_handler;
+               return ret;
        }
+       cdev->handler = &dasd_int_handler;
 
+       /*
+        * Automatically online either all dasd devices (dasd_autodetect)
+        * or all devices specified with dasd= parameters during
+        * initial probe.
+        */
+       if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) ||
+           (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0))
+               ret = ccw_device_set_online(cdev);
+       if (ret)
+               printk(KERN_WARNING
+                      "dasd_generic_probe: could not initially online "
+                      "ccw-device %s\n", cdev->dev.bus_id);
        return ret;
 }
 
@@ -1911,6 +1929,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
        struct dasd_device *device;
        int rc;
 
+       /* first online clears initial online feature flag */
+       dasd_set_feature(cdev, DASD_FEATURE_INITIAL_ONLINE, 0);
        device = dasd_create_device(cdev);
        if (IS_ERR(device))
                return PTR_ERR(device);
@@ -2065,31 +2085,6 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
        return ret;
 }
 
-/*
- * Automatically online either all dasd devices (dasd_autodetect) or
- * all devices specified with dasd= parameters.
- */
-static int
-__dasd_auto_online(struct device *dev, void *data)
-{
-       struct ccw_device *cdev;
-
-       cdev = to_ccwdev(dev);
-       if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0)
-               ccw_device_set_online(cdev);
-       return 0;
-}
-
-void
-dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
-{
-       struct device_driver *drv;
-
-       drv = get_driver(&dasd_discipline_driver->driver);
-       driver_for_each_device(drv, NULL, NULL, __dasd_auto_online);
-       put_driver(drv);
-}
-
 
 static int __init
 dasd_init(void)
@@ -2111,9 +2106,6 @@ dasd_init(void)
 
        dasd_diag_discipline_pointer = NULL;
 
-       rc = devfs_mk_dir("dasd");
-       if (rc)
-               goto failed;
        rc = dasd_devmap_init();
        if (rc)
                goto failed;
@@ -2170,23 +2162,4 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove);
 EXPORT_SYMBOL_GPL(dasd_generic_notify);
 EXPORT_SYMBOL_GPL(dasd_generic_set_online);
 EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
-EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
 
-/*
- * 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: 1
- * tab-width: 8
- * End:
- */
index 1d11c2a9525d3d1ab7f158efd6f96df53e541949..1ddab8991d92fe1020c1c8309180d175700f954b 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_3370_erp.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
 
 
 /*
- * DASD_3370_ERP_EXAMINE 
+ * DASD_3370_ERP_EXAMINE
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recover error. 
+ *   Checks only for fatal/no/recover error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
@@ -23,7 +23,7 @@
  *   'Chapter 7. 3370 Sense Data'.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for all others.
  */
@@ -82,22 +82,3 @@ dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
        return dasd_era_recover;
 
 }                              /* END dasd_3370_erp_examine */
-
-/*
- * 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: 1
- * tab-width: 8
- * End:
- */
index 2ed51562319eae9541b6f2dda331bb3818aac75b..669805d4402dcdf628424cb0ff49900db9ba50ad 100644 (file)
@@ -1,6 +1,6 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_3990_erp.c
- * Author(s)......: Horst  Hummel    <Horst.Hummel@de.ibm.com> 
+ * Author(s)......: Horst  Hummel    <Horst.Hummel@de.ibm.com>
  *                 Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
@@ -25,23 +25,23 @@ struct DCTL_data {
 } __attribute__ ((packed));
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * SECTION ERP EXAMINATION
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERP_EXAMINE_24 
+ * DASD_3990_ERP_EXAMINE_24
  *
  * DESCRIPTION
- *   Checks only for fatal (unrecoverable) error. 
+ *   Checks only for fatal (unrecoverable) error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
  *   Each bit configuration leading to an action code 2 (Exit with
  *   programming error or unusual condition indication)
  *   are handled as fatal error´s.
- * 
+ *
  *   All other configurations are handled as recoverable errors.
  *
  * RETURN VALUES
@@ -93,15 +93,15 @@ dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense)
 }                              /* END dasd_3990_erp_examine_24 */
 
 /*
- * DASD_3990_ERP_EXAMINE_32 
+ * DASD_3990_ERP_EXAMINE_32
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recoverable error. 
+ *   Checks only for fatal/no/recoverable error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for recoverable others.
  */
@@ -128,10 +128,10 @@ dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
 }                              /* end dasd_3990_erp_examine_32 */
 
 /*
- * DASD_3990_ERP_EXAMINE 
+ * DASD_3990_ERP_EXAMINE
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recover error. 
+ *   Checks only for fatal/no/recover error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
@@ -139,7 +139,7 @@ dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
  *   'Chapter 7. Error Recovery Procedures'.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for all others.
  */
@@ -178,18 +178,18 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
 }                              /* END dasd_3990_erp_examine */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * SECTION ERP HANDLING
- ***************************************************************************** 
+ *****************************************************************************
  */
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * 24 and 32 byte sense ERP functions
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERP_CLEANUP 
+ * DASD_3990_ERP_CLEANUP
  *
  * DESCRIPTION
  *   Removes the already build but not necessary ERP request and sets
@@ -197,10 +197,10 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
  *
  *  PARAMETER
  *   erp               request to be blocked
- *   final_status      either DASD_CQR_DONE or DASD_CQR_FAILED 
+ *   final_status      either DASD_CQR_DONE or DASD_CQR_FAILED
  *
  * RETURN VALUES
- *   cqr               original cqr               
+ *   cqr               original cqr
  */
 static struct dasd_ccw_req *
 dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
@@ -214,7 +214,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
 }                              /* end dasd_3990_erp_cleanup */
 
 /*
- * DASD_3990_ERP_BLOCK_QUEUE 
+ * DASD_3990_ERP_BLOCK_QUEUE
  *
  * DESCRIPTION
  *   Block the given device request queue to prevent from further
@@ -237,7 +237,7 @@ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
 }
 
 /*
- * DASD_3990_ERP_INT_REQ 
+ * DASD_3990_ERP_INT_REQ
  *
  * DESCRIPTION
  *   Handles 'Intervention Required' error.
@@ -277,7 +277,7 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
 }                              /* end dasd_3990_erp_int_req */
 
 /*
- * DASD_3990_ERP_ALTERNATE_PATH 
+ * DASD_3990_ERP_ALTERNATE_PATH
  *
  * DESCRIPTION
  *   Repeat the operation on a different channel path.
@@ -330,15 +330,15 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
  * DASD_3990_ERP_DCTL
  *
  * DESCRIPTION
- *   Setup cqr to do the Diagnostic Control (DCTL) command with an 
+ *   Setup cqr to do the Diagnostic Control (DCTL) command with an
  *   Inhibit Write subcommand (0x20) and the given modifier.
  *
  *  PARAMETER
  *   erp               pointer to the current (failed) ERP
  *   modifier          subcommand modifier
- *   
+ *
  * RETURN VALUES
- *   dctl_cqr          pointer to NEW dctl_cqr 
+ *   dctl_cqr          pointer to NEW dctl_cqr
  *
  */
 static struct dasd_ccw_req *
@@ -386,7 +386,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
 }                              /* end dasd_3990_erp_DCTL */
 
 /*
- * DASD_3990_ERP_ACTION_1 
+ * DASD_3990_ERP_ACTION_1
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 1 (see Reference manual).
@@ -415,7 +415,7 @@ dasd_3990_erp_action_1(struct dasd_ccw_req * erp)
 }                              /* end dasd_3990_erp_action_1 */
 
 /*
- * DASD_3990_ERP_ACTION_4 
+ * DASD_3990_ERP_ACTION_4
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 4 (see Reference manual).
@@ -453,11 +453,11 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 
                if (sense[25] == 0x1D) {        /* state change pending */
 
-                       DEV_MESSAGE(KERN_INFO, device, 
+                       DEV_MESSAGE(KERN_INFO, device,
                                    "waiting for state change pending "
                                    "interrupt, %d retries left",
                                    erp->retries);
-                       
+
                        dasd_3990_erp_block_queue(erp, 30*HZ);
 
                 } else if (sense[25] == 0x1E) {        /* busy */
@@ -469,9 +469,9 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
                } else {
 
                        /* no state change pending - retry */
-                       DEV_MESSAGE (KERN_INFO, device, 
+                       DEV_MESSAGE (KERN_INFO, device,
                                     "redriving request immediately, "
-                                    "%d retries left", 
+                                    "%d retries left",
                                     erp->retries);
                        erp->status = DASD_CQR_QUEUED;
                }
@@ -482,13 +482,13 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_action_4 */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * 24 byte sense ERP functions (only)
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERP_ACTION_5 
+ * DASD_3990_ERP_ACTION_5
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 5 (see Reference manual).
@@ -523,7 +523,7 @@ dasd_3990_erp_action_5(struct dasd_ccw_req * erp)
  *
  * PARAMETER
  *   sense             current sense data
- *   
+ *
  * RETURN VALUES
  *   void
  */
@@ -1150,9 +1150,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
  * PARAMETER
  *   erp               current erp_head
  *   sense             current sense data
- * 
+ *
  * RETURN VALUES
- *   erp               'new' erp_head - pointer to new ERP 
+ *   erp               'new' erp_head - pointer to new ERP
  */
 static struct dasd_ccw_req *
 dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
@@ -1185,7 +1185,7 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_com_rej */
 
 /*
- * DASD_3990_ERP_BUS_OUT 
+ * DASD_3990_ERP_BUS_OUT
  *
  * DESCRIPTION
  *   Handles 24 byte 'Bus Out Parity Check' error.
@@ -1483,7 +1483,7 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
  *
  * PARAMETER
  *   erp               already added default ERP
- *             
+ *
  * RETURN VALUES
  *   erp               new erp_head - pointer to new ERP
  */
@@ -1527,11 +1527,11 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
 }                              /* end dasd_3990_erp_file_prot */
 
 /*
- * DASD_3990_ERP_INSPECT_24 
+ * DASD_3990_ERP_INSPECT_24
  *
  * DESCRIPTION
  *   Does a detailed inspection of the 24 byte sense data
- *   and sets up a related error recovery action.  
+ *   and sets up a related error recovery action.
  *
  * PARAMETER
  *   sense             sense data of the actual error
@@ -1602,13 +1602,13 @@ dasd_3990_erp_inspect_24(struct dasd_ccw_req * erp, char *sense)
 }                              /* END dasd_3990_erp_inspect_24 */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * 32 byte sense ERP functions (only)
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
- * DASD_3990_ERPACTION_10_32 
+ * DASD_3990_ERPACTION_10_32
  *
  * DESCRIPTION
  *   Handles 32 byte 'Action 10' of Single Program Action Codes.
@@ -1616,7 +1616,7 @@ dasd_3990_erp_inspect_24(struct dasd_ccw_req * erp, char *sense)
  *
  * PARAMETER
  *   erp               current erp_head
- *   sense             current sense data 
+ *   sense             current sense data
  * RETURN VALUES
  *   erp               modified erp_head
  */
@@ -1640,18 +1640,18 @@ dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)
  *
  * DESCRIPTION
  *   Handles 32 byte 'Action 1B' of Single Program Action Codes.
- *   A write operation could not be finished because of an unexpected 
+ *   A write operation could not be finished because of an unexpected
  *   condition.
- *   The already created 'default erp' is used to get the link to 
- *   the erp chain, but it can not be used for this recovery 
+ *   The already created 'default erp' is used to get the link to
+ *   the erp chain, but it can not be used for this recovery
  *   action because it contains no DE/LO data space.
  *
  * PARAMETER
  *   default_erp       already added default erp.
- *   sense             current sense data 
+ *   sense             current sense data
  *
  * RETURN VALUES
- *   erp               new erp or 
+ *   erp               new erp or
  *                     default_erp in case of imprecise ending or error
  */
 static struct dasd_ccw_req *
@@ -1789,16 +1789,16 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
  * DASD_3990_UPDATE_1B
  *
  * DESCRIPTION
- *   Handles the update to the 32 byte 'Action 1B' of Single Program 
+ *   Handles the update to the 32 byte 'Action 1B' of Single Program
  *   Action Codes in case the first action was not successful.
  *   The already created 'previous_erp' is the currently not successful
- *   ERP. 
+ *   ERP.
  *
  * PARAMETER
  *   previous_erp      already created previous erp.
- *   sense             current sense data 
+ *   sense             current sense data
  * RETURN VALUES
- *   erp               modified erp 
+ *   erp               modified erp
  */
 static struct dasd_ccw_req *
 dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
@@ -1897,7 +1897,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 }                              /* end dasd_3990_update_1B */
 
 /*
- * DASD_3990_ERP_COMPOUND_RETRY 
+ * DASD_3990_ERP_COMPOUND_RETRY
  *
  * DESCRIPTION
  *   Handles the compound ERP action retry code.
@@ -1943,7 +1943,7 @@ dasd_3990_erp_compound_retry(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_retry */
 
 /*
- * DASD_3990_ERP_COMPOUND_PATH 
+ * DASD_3990_ERP_COMPOUND_PATH
  *
  * DESCRIPTION
  *   Handles the compound ERP action for retry on alternate
@@ -1965,7 +1965,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
                dasd_3990_erp_alternate_path(erp);
 
                if (erp->status == DASD_CQR_FAILED) {
-                       /* reset the lpm and the status to be able to 
+                       /* reset the lpm and the status to be able to
                         * try further actions. */
 
                        erp->lpm = 0;
@@ -1980,7 +1980,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_path */
 
 /*
- * DASD_3990_ERP_COMPOUND_CODE 
+ * DASD_3990_ERP_COMPOUND_CODE
  *
  * DESCRIPTION
  *   Handles the compound ERP action for retry code.
@@ -2001,18 +2001,18 @@ dasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense)
 
                switch (sense[28]) {
                case 0x17:
-                       /* issue a Diagnostic Control command with an 
+                       /* issue a Diagnostic Control command with an
                         * Inhibit Write subcommand and controler modifier */
                        erp = dasd_3990_erp_DCTL(erp, 0x20);
                        break;
-                       
+
                case 0x25:
                        /* wait for 5 seconds and retry again */
                        erp->retries = 1;
-                       
+
                        dasd_3990_erp_block_queue (erp, 5*HZ);
                        break;
-                       
+
                default:
                        /* should not happen - continue */
                        break;
@@ -2026,7 +2026,7 @@ dasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_code */
 
 /*
- * DASD_3990_ERP_COMPOUND_CONFIG 
+ * DASD_3990_ERP_COMPOUND_CONFIG
  *
  * DESCRIPTION
  *   Handles the compound ERP action for configruation
@@ -2063,10 +2063,10 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound_config */
 
 /*
- * DASD_3990_ERP_COMPOUND 
+ * DASD_3990_ERP_COMPOUND
  *
  * DESCRIPTION
- *   Does the further compound program action if 
+ *   Does the further compound program action if
  *   compound retry was not successful.
  *
  * PARAMETER
@@ -2110,11 +2110,11 @@ dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_compound */
 
 /*
- * DASD_3990_ERP_INSPECT_32 
+ * DASD_3990_ERP_INSPECT_32
  *
  * DESCRIPTION
  *   Does a detailed inspection of the 32 byte sense data
- *   and sets up a related error recovery action.  
+ *   and sets up a related error recovery action.
  *
  * PARAMETER
  *   sense             sense data of the actual error
@@ -2228,9 +2228,9 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
 }                              /* end dasd_3990_erp_inspect_32 */
 
 /*
- ***************************************************************************** 
+ *****************************************************************************
  * main ERP control fuctions (24 and 32 byte sense)
- ***************************************************************************** 
+ *****************************************************************************
  */
 
 /*
@@ -2243,7 +2243,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
  * PARAMETER
  *   erp               pointer to the currently created default ERP
  * RETURN VALUES
- *   erp_new           contens was possibly modified 
+ *   erp_new           contens was possibly modified
  */
 static struct dasd_ccw_req *
 dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
@@ -2272,14 +2272,14 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
 
 /*
  * DASD_3990_ERP_ADD_ERP
- * 
+ *
  * DESCRIPTION
  *   This funtion adds an additional request block (ERP) to the head of
  *   the given cqr (or erp).
  *   This erp is initialized as an default erp (retry TIC)
  *
  * PARAMETER
- *   cqr               head of the current ERP-chain (or single cqr if 
+ *   cqr               head of the current ERP-chain (or single cqr if
  *                     first error)
  * RETURN VALUES
  *   erp               pointer to new ERP-chain head
@@ -2332,15 +2332,15 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
 }
 
 /*
- * DASD_3990_ERP_ADDITIONAL_ERP 
- * 
+ * DASD_3990_ERP_ADDITIONAL_ERP
+ *
  * DESCRIPTION
  *   An additional ERP is needed to handle the current error.
  *   Add ERP to the head of the ERP-chain containing the ERP processing
  *   determined based on the sense data.
  *
  * PARAMETER
- *   cqr               head of the current ERP-chain (or single cqr if 
+ *   cqr               head of the current ERP-chain (or single cqr if
  *                     first error)
  *
  * RETURN VALUES
@@ -2376,7 +2376,7 @@ dasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr)
  *   24 byte sense byte 25 and 27 is set as well.
  *
  * PARAMETER
- *   cqr1              first cqr, which will be compared with the 
+ *   cqr1              first cqr, which will be compared with the
  *   cqr2              second cqr.
  *
  * RETURN VALUES
@@ -2415,7 +2415,7 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2)
  *   cqr               failed cqr (either original cqr or already an erp)
  *
  * RETURN VALUES
- *   erp               erp-pointer to the already defined error 
+ *   erp               erp-pointer to the already defined error
  *                     recovery procedure OR
  *                     NULL if a 'new' error occurred.
  */
@@ -2451,10 +2451,10 @@ dasd_3990_erp_in_erp(struct dasd_ccw_req *cqr)
  * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense)
  *
  * DESCRIPTION
- *   No retry is left for the current ERP. Check what has to be done 
+ *   No retry is left for the current ERP. Check what has to be done
  *   with the ERP.
  *     - do further defined ERP action or
- *     - wait for interrupt or 
+ *     - wait for interrupt or
  *     - exit with permanent error
  *
  * PARAMETER
@@ -2485,7 +2485,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
 
                if (!(sense[2] & DASD_SENSE_BIT_0)) {
 
-                       /* issue a Diagnostic Control command with an 
+                       /* issue a Diagnostic Control command with an
                         * Inhibit Write subcommand */
 
                        switch (sense[25]) {
@@ -2535,14 +2535,14 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
 }                              /* end dasd_3990_erp_further_erp */
 
 /*
- * DASD_3990_ERP_HANDLE_MATCH_ERP 
+ * DASD_3990_ERP_HANDLE_MATCH_ERP
  *
  * DESCRIPTION
  *   An error occurred again and an ERP has been detected which is already
- *   used to handle this error (e.g. retries). 
+ *   used to handle this error (e.g. retries).
  *   All prior ERP's are asumed to be successful and therefore removed
  *   from queue.
- *   If retry counter of matching erp is already 0, it is checked if further 
+ *   If retry counter of matching erp is already 0, it is checked if further
  *   action is needed (besides retry) or if the ERP has failed.
  *
  * PARAMETER
@@ -2631,7 +2631,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
  *   erp               erp-pointer to the head of the ERP action chain.
  *                     This means:
  *                      - either a ptr to an additional ERP cqr or
- *                      - the original given cqr (which's status might 
+ *                      - the original given cqr (which's status might
  *                        be modified)
  */
 struct dasd_ccw_req *
@@ -2723,22 +2723,3 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
        return erp;
 
 }                              /* end dasd_3990_erp_action */
-
-/*
- * 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: 1
- * tab-width: 8
- * End:
- */
index dc861446d0562b991427433df7605111429a818e..6e082688475a8f31352cefeebc46aff0ed3ba63e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_9336_erp.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
 
 
 /*
- * DASD_9336_ERP_EXAMINE 
+ * DASD_9336_ERP_EXAMINE
  *
  * DESCRIPTION
- *   Checks only for fatal/no/recover error. 
+ *   Checks only for fatal/no/recover error.
  *   A detailed examination of the sense data is done later outside
  *   the interrupt handler.
  *
@@ -23,7 +23,7 @@
  *   'Chapter 7. 9336 Sense Data'.
  *
  * RETURN VALUES
- *   dasd_era_none     no error 
+ *   dasd_era_none     no error
  *   dasd_era_fatal    for all fatal (unrecoverable errors)
  *   dasd_era_recover  for all others.
  */
@@ -39,22 +39,3 @@ dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
        return dasd_era_recover;
 
 }                              /* END dasd_9336_erp_examine */
-
-/*
- * 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: 1
- * tab-width: 8
- * End:
- */
index 4a5b79569aaaa463461f55a25dffc09f0d9b3b32..ddecb9808ed4b1c08e22399b8bb7151fc0cd636e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_9345_erp.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
index 216bc4fba19998c2c5a92a8455d92f32d0dce4ab..9e9ae71796028162b94d45316776ec2b2f7f0d6b 100644 (file)
@@ -27,7 +27,7 @@
 #include "dasd_int.h"
 
 kmem_cache_t *dasd_page_cache;
-EXPORT_SYMBOL(dasd_page_cache);
+EXPORT_SYMBOL_GPL(dasd_page_cache);
 
 /*
  * dasd_devmap_t is used to store the features and the relation
@@ -48,6 +48,20 @@ struct dasd_devmap {
        struct dasd_uid uid;
 };
 
+/*
+ * dasd_servermap is used to store the server_id of all storage servers
+ * accessed by DASD device driver.
+ */
+struct dasd_servermap {
+       struct list_head list;
+       struct server_id {
+               char vendor[4];
+               char serial[15];
+       } sid;
+};
+
+static struct list_head dasd_serverlist;
+
 /*
  * Parameter parsing functions for dasd= parameter. The syntax is:
  *   <devno>           : (0x)?[0-9a-fA-F]+
@@ -64,6 +78,8 @@ struct dasd_devmap {
 
 int dasd_probeonly =  0;       /* is true, when probeonly mode is active */
 int dasd_autodetect = 0;       /* is true, when autodetection is active */
+int dasd_nopav = 0;            /* is true, when PAV is disabled */
+EXPORT_SYMBOL_GPL(dasd_nopav);
 
 /*
  * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
@@ -123,7 +139,7 @@ static inline int
 dasd_busid(char **str, int *id0, int *id1, int *devno)
 {
        int val, old_style;
+
        /* check for leading '0x' */
        old_style = 0;
        if ((*str)[0] == '0' && (*str)[1] == 'x') {
@@ -179,7 +195,7 @@ dasd_feature_list(char *str, char **endp)
        features = 0;
 
        while (1) {
-               for (len = 0; 
+               for (len = 0;
                     str[len] && str[len] != ':' && str[len] != ')'; len++);
                if (len == 2 && !strncmp(str, "ro", 2))
                        features |= DASD_FEATURE_READONLY;
@@ -228,19 +244,24 @@ dasd_parse_keyword( char *parsestring ) {
                length = strlen(parsestring);
                residual_str = parsestring + length;
         }
-       if (strncmp ("autodetect", parsestring, length) == 0) {
+       if (strncmp("autodetect", parsestring, length) == 0) {
                dasd_autodetect = 1;
                MESSAGE (KERN_INFO, "%s",
                         "turning to autodetection mode");
                 return residual_str;
         }
-        if (strncmp ("probeonly", parsestring, length) == 0) {
+       if (strncmp("probeonly", parsestring, length) == 0) {
                dasd_probeonly = 1;
                MESSAGE(KERN_INFO, "%s",
                        "turning to probeonly mode");
                 return residual_str;
         }
-        if (strncmp ("fixedbuffers", parsestring, length) == 0) {
+       if (strncmp("nopav", parsestring, length) == 0) {
+               dasd_nopav = 1;
+               MESSAGE(KERN_INFO, "%s", "disable PAV mode");
+               return residual_str;
+       }
+       if (strncmp("fixedbuffers", parsestring, length) == 0) {
                if (dasd_page_cache)
                        return residual_str;
                dasd_page_cache =
@@ -294,6 +315,8 @@ dasd_parse_range( char *parsestring ) {
        features = dasd_feature_list(str, &str);
        if (features < 0)
                return ERR_PTR(-EINVAL);
+       /* each device in dasd= parameter should be set initially online */
+       features |= DASD_FEATURE_INITIAL_ONLINE;
        while (from <= to) {
                sprintf(bus_id, "%01x.%01x.%04x",
                        from_id0, from_id1, from++);
@@ -359,7 +382,7 @@ dasd_parse(void)
  * Add a devmap for the device specified by busid. It is possible that
  * the devmap already exists (dasd= parameter). The order of the devices
  * added through this function will define the kdevs for the individual
- * devices. 
+ * devices.
  */
 static struct dasd_devmap *
 dasd_add_busid(char *bus_id, int features)
@@ -368,7 +391,7 @@ dasd_add_busid(char *bus_id, int features)
        int hash;
 
        new = (struct dasd_devmap *)
-               kmalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
+               kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
        if (!new)
                return ERR_PTR(-ENOMEM);
        spin_lock(&dasd_devmap_lock);
@@ -630,7 +653,8 @@ dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 
 static ssize_t
-dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+dasd_ro_store(struct device *dev, struct device_attribute *attr,
+             const char *buf, size_t count)
 {
        struct dasd_devmap *devmap;
        int ro_flag;
@@ -658,7 +682,7 @@ static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
  * use_diag controls whether the driver should use diag rather than ssch
  * to talk to the device
  */
-static ssize_t 
+static ssize_t
 dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct dasd_devmap *devmap;
@@ -673,7 +697,8 @@ dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 
 static ssize_t
-dasd_use_diag_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+dasd_use_diag_store(struct device *dev, struct device_attribute *attr,
+                   const char *buf, size_t count)
 {
        struct dasd_devmap *devmap;
        ssize_t rc;
@@ -697,11 +722,11 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, const cha
        return rc;
 }
 
-static
-DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
+static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
 
 static ssize_t
-dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *buf)
+dasd_discipline_show(struct device *dev, struct device_attribute *attr,
+                    char *buf)
 {
        struct dasd_devmap *devmap;
        char *dname;
@@ -834,6 +859,38 @@ static struct attribute_group dasd_attr_group = {
        .attrs = dasd_attrs,
 };
 
+/*
+ * Check if the related storage server is already contained in the
+ * dasd_serverlist. If server is not contained, create new entry.
+ * Return 0 if server was already in serverlist,
+ *       1 if the server was added successfully
+ *      <0 in case of error.
+ */
+static int
+dasd_add_server(struct dasd_uid *uid)
+{
+       struct dasd_servermap *new, *tmp;
+
+       /* check if server is already contained */
+       list_for_each_entry(tmp, &dasd_serverlist, list)
+         // normale cmp?
+               if (strncmp(tmp->sid.vendor, uid->vendor,
+                           sizeof(tmp->sid.vendor)) == 0
+                   && strncmp(tmp->sid.serial, uid->serial,
+                              sizeof(tmp->sid.serial)) == 0)
+                       return 0;
+
+       new = (struct dasd_servermap *)
+               kzalloc(sizeof(struct dasd_servermap), GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
+
+       strncpy(new->sid.vendor, uid->vendor, sizeof(new->sid.vendor));
+       strncpy(new->sid.serial, uid->serial, sizeof(new->sid.serial));
+       list_add(&new->list, &dasd_serverlist);
+       return 1;
+}
+
 
 /*
  * Return copy of the device unique identifier.
@@ -854,21 +911,26 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
 
 /*
  * Register the given device unique identifier into devmap struct.
+ * Return 0 if server was already in serverlist,
+ *       1 if the server was added successful
+ *      <0 in case of error.
  */
 int
 dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
 {
        struct dasd_devmap *devmap;
+       int rc;
 
        devmap = dasd_find_busid(cdev->dev.bus_id);
        if (IS_ERR(devmap))
                return PTR_ERR(devmap);
        spin_lock(&dasd_devmap_lock);
        devmap->uid = *uid;
+       rc = dasd_add_server(uid);
        spin_unlock(&dasd_devmap_lock);
-       return 0;
+       return rc;
 }
-EXPORT_SYMBOL(dasd_set_uid);
+EXPORT_SYMBOL_GPL(dasd_set_uid);
 
 /*
  * Return value of the specified feature.
@@ -880,7 +942,7 @@ dasd_get_feature(struct ccw_device *cdev, int feature)
 
        devmap = dasd_find_busid(cdev->dev.bus_id);
        if (IS_ERR(devmap))
-               return (int) PTR_ERR(devmap);
+               return PTR_ERR(devmap);
 
        return ((devmap->features & feature) != 0);
 }
@@ -896,7 +958,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
 
        devmap = dasd_find_busid(cdev->dev.bus_id);
        if (IS_ERR(devmap))
-               return (int) PTR_ERR(devmap);
+               return PTR_ERR(devmap);
 
        spin_lock(&dasd_devmap_lock);
        if (flag)
@@ -932,8 +994,10 @@ dasd_devmap_init(void)
        dasd_max_devindex = 0;
        for (i = 0; i < 256; i++)
                INIT_LIST_HEAD(&dasd_hashlists[i]);
-       return 0;
 
+       /* Initialize servermap structure. */
+       INIT_LIST_HEAD(&dasd_serverlist);
+       return 0;
 }
 
 void
index 3f9d704d2657483f739dcced896a212413665882..4002f6c1c1b3222a01b1fa2ced3b8df3da0fe043 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_diag.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Based on.......: linux/drivers/s390/block/mdisk.c
@@ -336,7 +336,7 @@ dasd_diag_check_device(struct dasd_device *device)
 
        private = (struct dasd_diag_private *) device->private;
        if (private == NULL) {
-               private = kmalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
+               private = kzalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
                if (private == NULL) {
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
                                "memory allocation failed for private data");
@@ -527,7 +527,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
                                   datasize, device);
        if (IS_ERR(cqr))
                return cqr;
-       
+
        dreq = (struct dasd_diag_req *) cqr->data;
        dreq->block_count = count;
        dbio = dreq->bio;
index 38a4e55f89539b90f514ea9f80b77d4f4d139475..b8c78267ff3ef01ef0e60a1e211784629f2f094e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_diag.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Based on.......: linux/drivers/s390/block/mdisk.h
index 7d5a6cee4bd8ff075c4c48ed6edccdb30cefb283..0dfab30e8089814ca75b1320ce4114a0942dcb8a 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_eckd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                 Horst Hummel <Horst.Hummel@de.ibm.com> 
+ *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  *                 Carsten Otte <Cotte@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
@@ -24,6 +24,7 @@
 #include <asm/io.h>
 #include <asm/todclk.h>
 #include <asm/uaccess.h>
+#include <asm/cio.h>
 #include <asm/ccwdev.h>
 
 #include "dasd_int.h"
@@ -89,17 +90,22 @@ dasd_eckd_probe (struct ccw_device *cdev)
 {
        int ret;
 
-       ret = dasd_generic_probe (cdev, &dasd_eckd_discipline);
-       if (ret)
+       /* set ECKD specific ccw-device options */
+       ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);
+       if (ret) {
+               printk(KERN_WARNING
+                      "dasd_eckd_probe: could not set ccw-device options "
+                      "for %s\n", cdev->dev.bus_id);
                return ret;
-       ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP | CCWDEV_ALLOW_FORCE);
-       return 0;
+       }
+       ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
+       return ret;
 }
 
 static int
 dasd_eckd_set_online(struct ccw_device *cdev)
 {
-       return dasd_generic_set_online (cdev, &dasd_eckd_discipline);
+       return dasd_generic_set_online(cdev, &dasd_eckd_discipline);
 }
 
 static struct ccw_driver dasd_eckd_driver = {
@@ -210,14 +216,14 @@ check_XRC (struct ccw1         *de_ccw,
 
         /* switch on System Time Stamp - needed for XRC Support */
         if (private->rdc_data.facilities.XRC_supported) {
-                
+
                 data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
                 data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
-                
+
                 data->ep_sys_time = get_clock ();
-                
+
                 de_ccw->count = sizeof (struct DE_eckd_data);
-                de_ccw->flags |= CCW_FLAG_SLI;  
+               de_ccw->flags |= CCW_FLAG_SLI;
         }
 
         return;
@@ -296,8 +302,8 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
        /* check for sequential prestage - enhance cylinder range */
        if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
            data->attributes.operation == DASD_SEQ_ACCESS) {
-               
-               if (end.cyl + private->attrib.nr_cyl < geo.cyl) 
+
+               if (end.cyl + private->attrib.nr_cyl < geo.cyl)
                        end.cyl += private->attrib.nr_cyl;
                else
                        end.cyl = (geo.cyl - 1);
@@ -317,7 +323,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
        struct dasd_eckd_private *private;
        int sector;
        int dn, d;
-                               
+
        private = (struct dasd_eckd_private *) device->private;
 
        DBF_DEV_EVENT(DBF_INFO, device,
@@ -540,6 +546,86 @@ dasd_eckd_read_conf(struct dasd_device *device)
        return 0;
 }
 
+/*
+ * Build CP for Perform Subsystem Function - SSC.
+ */
+struct dasd_ccw_req *
+dasd_eckd_build_psf_ssc(struct dasd_device *device)
+{
+       struct dasd_ccw_req *cqr;
+       struct dasd_psf_ssc_data *psf_ssc_data;
+       struct ccw1 *ccw;
+
+       cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
+                                 sizeof(struct dasd_psf_ssc_data),
+                                 device);
+
+       if (IS_ERR(cqr)) {
+              DEV_MESSAGE(KERN_WARNING, device, "%s",
+                          "Could not allocate PSF-SSC request");
+              return cqr;
+       }
+       psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
+       psf_ssc_data->order = PSF_ORDER_SSC;
+       psf_ssc_data->suborder = 0x08;
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->cda = (__u32)(addr_t)psf_ssc_data;
+       ccw->count = 66;
+
+       cqr->device = device;
+       cqr->expires = 10*HZ;
+       cqr->buildclk = get_clock();
+       cqr->status = DASD_CQR_FILLED;
+       return cqr;
+}
+
+/*
+ * Perform Subsystem Function.
+ * It is necessary to trigger CIO for channel revalidation since this
+ * call might change behaviour of DASD devices.
+ */
+static int
+dasd_eckd_psf_ssc(struct dasd_device *device)
+{
+       struct dasd_ccw_req *cqr;
+       int rc;
+
+       cqr = dasd_eckd_build_psf_ssc(device);
+       if (IS_ERR(cqr))
+              return PTR_ERR(cqr);
+
+       rc = dasd_sleep_on(cqr);
+       if (!rc)
+              /* trigger CIO to reprobe devices */
+              css_schedule_reprobe();
+       dasd_sfree_request(cqr, cqr->device);
+       return rc;
+}
+
+/*
+ * Valide storage server of current device.
+ */
+static int
+dasd_eckd_validate_server(struct dasd_device *device)
+{
+       int rc;
+
+       /* Currently PAV is the only reason to 'validate' server on LPAR */
+       if (dasd_nopav || MACHINE_IS_VM)
+               return 0;
+
+       rc = dasd_eckd_psf_ssc(device);
+       if (rc)
+               /* may be requested feature is not available on server,
+                * therefore just report error and go ahead */
+               DEV_MESSAGE(KERN_INFO, device,
+                           "Perform Subsystem Function returned rc=%d", rc);
+       /* RE-Read Configuration Data */
+       return dasd_eckd_read_conf(device);
+}
+
 /*
  * Check device characteristics.
  * If the device is accessible using ECKD discipline, the device is enabled.
@@ -554,7 +640,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
 
        private = (struct dasd_eckd_private *) device->private;
        if (private == NULL) {
-               private = kmalloc(sizeof(struct dasd_eckd_private),
+               private = kzalloc(sizeof(struct dasd_eckd_private),
                                  GFP_KERNEL | GFP_DMA);
                if (private == NULL) {
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
@@ -562,7 +648,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                                    "data");
                        return -ENOMEM;
                }
-               memset(private, 0, sizeof(struct dasd_eckd_private));
                device->private = (void *) private;
        }
        /* Invalidate status of initial analysis. */
@@ -571,16 +656,29 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        private->attrib.operation = DASD_NORMAL_CACHE;
        private->attrib.nr_cyl = 0;
 
+       /* Read Configuration Data */
+       rc = dasd_eckd_read_conf(device);
+       if (rc)
+               return rc;
+
+       /* Generate device unique id and register in devmap */
+       rc = dasd_eckd_generate_uid(device, &uid);
+       if (rc)
+               return rc;
+       rc = dasd_set_uid(device->cdev, &uid);
+       if (rc == 1)    /* new server found */
+               rc = dasd_eckd_validate_server(device);
+       if (rc)
+               return rc;
+
        /* Read Device Characteristics */
        rdc_data = (void *) &(private->rdc_data);
        memset(rdc_data, 0, sizeof(rdc_data));
        rc = read_dev_chars(device->cdev, &rdc_data, 64);
-       if (rc) {
+       if (rc)
                DEV_MESSAGE(KERN_WARNING, device,
-                           "Read device characteristics returned error %d",
-                           rc);
-               return rc;
-       }
+                           "Read device characteristics returned "
+                           "rc=%d", rc);
 
        DEV_MESSAGE(KERN_INFO, device,
                    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
@@ -591,19 +689,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                    private->rdc_data.no_cyl,
                    private->rdc_data.trk_per_cyl,
                    private->rdc_data.sec_per_trk);
-
-       /* Read Configuration Data */
-       rc = dasd_eckd_read_conf (device);
-       if (rc)
-               return rc;
-
-       /* Generate device unique id and register in devmap */
-       rc = dasd_eckd_generate_uid(device, &uid);
-       if (rc)
-               return rc;
-
-       rc = dasd_set_uid(device->cdev, &uid);
-
        return rc;
 }
 
@@ -773,7 +858,7 @@ dasd_eckd_end_analysis(struct dasd_device *device)
                    ((private->rdc_data.no_cyl *
                      private->rdc_data.trk_per_cyl *
                      blk_per_trk * (device->bp_block >> 9)) >> 1),
-                   ((blk_per_trk * device->bp_block) >> 10), 
+                   ((blk_per_trk * device->bp_block) >> 10),
                    private->uses_cdl ?
                    "compatible disk layout" : "linux disk layout");
 
@@ -970,7 +1055,7 @@ dasd_eckd_format_device(struct dasd_device * device,
                                if (i < 3) {
                                        ect->kl = 4;
                                        ect->dl = sizes_trk0[i] - 4;
-                               } 
+                               }
                        }
                        if ((fdata->intensity & 0x08) &&
                            fdata->start_unit == 1) {
@@ -1270,7 +1355,7 @@ dasd_eckd_fill_info(struct dasd_device * device,
 
 /*
  * Release device ioctl.
- * Buils a channel programm to releases a prior reserved 
+ * Buils a channel programm to releases a prior reserved
  * (see dasd_eckd_reserve) device.
  */
 static int
@@ -1310,8 +1395,8 @@ dasd_eckd_release(struct dasd_device *device)
 /*
  * Reserve device ioctl.
  * Options are set to 'synchronous wait for interrupt' and
- * 'timeout the request'. This leads to a terminate IO if 
- * the interrupt is outstanding for a certain time. 
+ * 'timeout the request'. This leads to a terminate IO if
+ * the interrupt is outstanding for a certain time.
  */
 static int
 dasd_eckd_reserve(struct dasd_device *device)
@@ -1349,7 +1434,7 @@ dasd_eckd_reserve(struct dasd_device *device)
 
 /*
  * Steal lock ioctl - unconditional reserve device.
- * Buils a channel programm to break a device's reservation. 
+ * Buils a channel programm to break a device's reservation.
  * (unconditional reserve)
  */
 static int
@@ -1521,6 +1606,40 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
        }
 }
 
+/*
+ * Dump the range of CCWs into 'page' buffer
+ * and return number of printed chars.
+ */
+static inline int
+dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
+{
+       int len, count;
+       char *datap;
+
+       len = 0;
+       while (from <= to) {
+               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+                              " CCW %p: %08X %08X DAT:",
+                              from, ((int *) from)[0], ((int *) from)[1]);
+
+               /* get pointer to data (consider IDALs) */
+               if (from->flags & CCW_FLAG_IDA)
+                       datap = (char *) *((addr_t *) (addr_t) from->cda);
+               else
+                       datap = (char *) ((addr_t) from->cda);
+
+               /* dump data (max 32 bytes) */
+               for (count = 0; count < from->count && count < 32; count++) {
+                       if (count % 8 == 0) len += sprintf(page + len, " ");
+                       if (count % 4 == 0) len += sprintf(page + len, " ");
+                       len += sprintf(page + len, "%02x", datap[count]);
+               }
+               len += sprintf(page + len, "\n");
+               from++;
+       }
+       return len;
+}
+
 /*
  * Print sense data and related channel program.
  * Parts are printed because printk buffer is only 1024 bytes.
@@ -1530,8 +1649,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                     struct irb *irb)
 {
        char *page;
-       struct ccw1 *act, *end, *last;
-       int len, sl, sct, count;
+       struct ccw1 *first, *last, *fail, *from, *to;
+       int len, sl, sct;
 
        page = (char *) get_zeroed_page(GFP_ATOMIC);
        if (page == NULL) {
@@ -1539,7 +1658,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                            "No memory to dump sense data");
                return;
        }
-       len = sprintf(page, KERN_ERR PRINTK_HEADER
+       /* dump the sense data */
+       len = sprintf(page,  KERN_ERR PRINTK_HEADER
                      " I/O status report for device %s:\n",
                      device->cdev->dev.bus_id);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
@@ -1564,87 +1684,55 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
 
                if (irb->ecw[27] & DASD_SENSE_BIT_0) {
                        /* 24 Byte Sense Data */
-                       len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                                      " 24 Byte: %x MSG %x, "
-                                      "%s MSGb to SYSOP\n",
-                                      irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
-                                      irb->ecw[1] & 0x10 ? "" : "no");
+                       sprintf(page + len, KERN_ERR PRINTK_HEADER
+                               " 24 Byte: %x MSG %x, "
+                               "%s MSGb to SYSOP\n",
+                               irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
+                               irb->ecw[1] & 0x10 ? "" : "no");
                } else {
                        /* 32 Byte Sense Data */
-                       len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                                      " 32 Byte: Format: %x "
-                                      "Exception class %x\n",
-                                      irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
+                       sprintf(page + len, KERN_ERR PRINTK_HEADER
+                               " 32 Byte: Format: %x "
+                               "Exception class %x\n",
+                               irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
                }
        } else {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " SORRY - NO VALID SENSE AVAILABLE\n");
+               sprintf(page + len, KERN_ERR PRINTK_HEADER
+                       " SORRY - NO VALID SENSE AVAILABLE\n");
        }
-       MESSAGE_LOG(KERN_ERR, "%s",
-                   page + sizeof(KERN_ERR PRINTK_HEADER));
-
-       /* dump the Channel Program */
-       /* print first CCWs (maximum 8) */
-       act = req->cpaddr;
-        for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
-       end = min(act + 8, last);
-       len = sprintf(page, KERN_ERR PRINTK_HEADER
+       printk("%s", page);
+
+       /* dump the Channel Program (max 140 Bytes per line) */
+       /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
+       first = req->cpaddr;
+       for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
+       to = min(first + 6, last);
+       len = sprintf(page,  KERN_ERR PRINTK_HEADER
                      " Related CP in req: %p\n", req);
-       while (act <= end) {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
-                              act, ((int *) act)[0], ((int *) act)[1]);
-               for (count = 0; count < 32 && count < act->count;
-                    count += sizeof(int))
-                       len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
-                                      [(count>>2)]);
-               len += sprintf(page + len, "\n");
-               act++;
-       }
-       MESSAGE_LOG(KERN_ERR, "%s",
-                   page + sizeof(KERN_ERR PRINTK_HEADER));
+       dasd_eckd_dump_ccw_range(first, to, page + len);
+       printk("%s", page);
 
-       /* print failing CCW area */
+       /* print failing CCW area (maximum 4) */
+       /* scsw->cda is either valid or zero  */
        len = 0;
-       if (act <  ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) {
-               act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2;
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
-       }
-       end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last);
-       while (act <= end) {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
-                              act, ((int *) act)[0], ((int *) act)[1]);
-               for (count = 0; count < 32 && count < act->count;
-                    count += sizeof(int))
-                       len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
-                                      [(count>>2)]);
-               len += sprintf(page + len, "\n");
-               act++;
+       from = ++to;
+       fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
+       if (from <  fail - 2) {
+               from = fail - 2;     /* there is a gap - print header */
+               len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
        }
+       to = min(fail + 1, last);
+       len += dasd_eckd_dump_ccw_range(from, to, page + len);
 
-       /* print last CCWs */
-       if (act <  last - 2) {
-               act = last - 2;
+       /* print last CCWs (maximum 2) */
+       from = max(from, ++to);
+       if (from < last - 1) {
+               from = last - 1;     /* there is a gap - print header */
                len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
        }
-       while (act <= last) {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
-                              act, ((int *) act)[0], ((int *) act)[1]);
-               for (count = 0; count < 32 && count < act->count;
-                    count += sizeof(int))
-                       len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
-                                      [(count>>2)]);
-               len += sprintf(page + len, "\n");
-               act++;
-       }
+       len += dasd_eckd_dump_ccw_range(from, last, page + len);
        if (len > 0)
-               MESSAGE_LOG(KERN_ERR, "%s",
-                           page + sizeof(KERN_ERR PRINTK_HEADER));
+               printk("%s", page);
        free_page((unsigned long) page);
 }
 
@@ -1685,14 +1773,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
 static int __init
 dasd_eckd_init(void)
 {
-       int ret;
-
        ASCEBC(dasd_eckd_discipline.ebcname, 4);
-
-       ret = ccw_driver_register(&dasd_eckd_driver);
-       if (!ret)
-               dasd_generic_auto_online(&dasd_eckd_driver);
-       return ret;
+       return ccw_driver_register(&dasd_eckd_driver);
 }
 
 static void __exit
@@ -1703,22 +1785,3 @@ dasd_eckd_cleanup(void)
 
 module_init(dasd_eckd_init);
 module_exit(dasd_eckd_cleanup);
-
-/*
- * 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: 1
- * tab-width: 8
- * End:
- */
index d5734e976e1c7da5fd599c52f83ba75a0f6e6e18..712ff1650134c5e1b60953758c922440231bd66d 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_eckd.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst Hummel <Horst.Hummel@de.ibm.com> 
+ *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
 #define DASD_ECKD_CCW_RESERVE           0xB4
 
 /*
- *Perform Subsystem Function / Sub-Orders
+ * Perform Subsystem Function / Sub-Orders
  */
-#define PSF_ORDER_PRSSD                         0x18
+#define PSF_ORDER_PRSSD 0x18
+#define PSF_ORDER_SSC  0x1D
 
 /*****************************************************************************
  * SECTION: Type Definitions
@@ -155,7 +156,7 @@ struct dasd_eckd_characteristics {
                unsigned char reserved2:4;
                unsigned char reserved3:8;
                unsigned char defect_wr:1;
-               unsigned char XRC_supported:1; 
+               unsigned char XRC_supported:1;
                unsigned char reserved4:1;
                unsigned char striping:1;
                unsigned char reserved5:4;
@@ -343,7 +344,7 @@ struct dasd_eckd_path {
 };
 
 /*
- * Perform Subsystem Function - Prepare for Read Subsystem Data         
+ * Perform Subsystem Function - Prepare for Read Subsystem Data
  */
 struct dasd_psf_prssd_data {
        unsigned char order;
@@ -353,4 +354,15 @@ struct dasd_psf_prssd_data {
        unsigned char varies[9];
 } __attribute__ ((packed));
 
+/*
+ * Perform Subsystem Function - Set Subsystem Characteristics
+ */
+struct dasd_psf_ssc_data {
+       unsigned char order;
+       unsigned char flags;
+       unsigned char cu_type[4];
+       unsigned char suborder;
+       unsigned char reserved[59];
+} __attribute__((packed));
+
 #endif                         /* DASD_ECKD_H */
index 2d946b6ca074cd0eea567e680ac00fabfd614d59..da65f1b032f5ad59748e356342afd1793eb0878e 100644 (file)
@@ -89,7 +89,7 @@ struct eerbuffer {
 };
 
 static LIST_HEAD(bufferlist);
-static spinlock_t bufferlock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(bufferlock);
 static DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue);
 
 /*
@@ -276,7 +276,7 @@ struct dasd_eer_header {
        __u64 tv_sec;
        __u64 tv_usec;
        char busid[DASD_EER_BUSID_SIZE];
-};
+} __attribute__ ((packed));
 
 /*
  * The following function can be used for those triggers that have
@@ -521,6 +521,8 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)
        unsigned long flags;
 
        eerb = kzalloc(sizeof(struct eerbuffer), GFP_KERNEL);
+       if (!eerb)
+               return -ENOMEM;
        eerb->buffer_page_count = eer_pages;
        if (eerb->buffer_page_count < 1 ||
            eerb->buffer_page_count > INT_MAX / PAGE_SIZE) {
index b842377cb0c6c51fa562ba364d4bcab4b2a0d07e..4108d96f6a5a8b9ae5622c79efc09f16adf38b04 100644 (file)
@@ -90,7 +90,7 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
 
         /* just retry - there is nothing to save ... I got no sense data.... */
         if (cqr->retries > 0) {
-                DEV_MESSAGE (KERN_DEBUG, device, 
+               DEV_MESSAGE (KERN_DEBUG, device,
                              "default ERP called (%i retries left)",
                              cqr->retries);
                cqr->lpm    = LPM_ANYPATH;
@@ -155,7 +155,7 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
 
 /*
  * Print the hex dump of the memory used by a request. This includes
- * all error recovery ccws that have been chained in from of the 
+ * all error recovery ccws that have been chained in from of the
  * real request.
  */
 static inline void
@@ -227,12 +227,12 @@ dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
                /*
                 * Log bytes arround failed CCW but only if we did
                 * not log the whole CP of the CCW is outside the
-                * logged CP. 
+                * logged CP.
                 */
                if (cplength > 40 ||
                    ((addr_t) cpa < (addr_t) lcqr->cpaddr &&
                     (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
-                       
+
                        DEV_MESSAGE(KERN_ERR, device,
                                    "Failed CCW (%p) (area):",
                                    (void *) (long) cpa);
index 91145698f8e926c7265e3d1581abf61479d62b9b..bb7755b9b19d7dfa408a9d79c959ff40f858468e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_fba.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
@@ -56,19 +56,13 @@ static struct ccw_driver dasd_fba_driver; /* see below */
 static int
 dasd_fba_probe(struct ccw_device *cdev)
 {
-       int ret;
-
-       ret = dasd_generic_probe (cdev, &dasd_fba_discipline);
-       if (ret)
-               return ret;
-       ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
-       return 0;
+       return dasd_generic_probe(cdev, &dasd_fba_discipline);
 }
 
 static int
 dasd_fba_set_online(struct ccw_device *cdev)
 {
-       return dasd_generic_set_online (cdev, &dasd_fba_discipline);
+       return dasd_generic_set_online(cdev, &dasd_fba_discipline);
 }
 
 static struct ccw_driver dasd_fba_driver = {
@@ -125,13 +119,13 @@ static int
 dasd_fba_check_characteristics(struct dasd_device *device)
 {
        struct dasd_fba_private *private;
-       struct ccw_device *cdev = device->cdev; 
+       struct ccw_device *cdev = device->cdev;
        void *rdc_data;
        int rc;
 
        private = (struct dasd_fba_private *) device->private;
        if (private == NULL) {
-               private = kmalloc(sizeof(struct dasd_fba_private), GFP_KERNEL);
+               private = kzalloc(sizeof(struct dasd_fba_private), GFP_KERNEL);
                if (private == NULL) {
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
                                    "memory allocation failed for private "
@@ -204,7 +198,7 @@ dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
        if (irb->scsw.cstat == 0x00 &&
            irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
                return dasd_era_none;
-       
+
        cdev = device->cdev;
        switch (cdev->id.dev_type) {
        case 0x3370:
@@ -539,7 +533,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
  * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
  * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use
  * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
- * addition we have one define extent ccw + 16 bytes of data and a 
+ * addition we have one define extent ccw + 16 bytes of data and a
  * locate record ccw for each block (stupid devices!) + 16 bytes of data.
  * That makes:
  * (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum.
@@ -569,16 +563,8 @@ static struct dasd_discipline dasd_fba_discipline = {
 static int __init
 dasd_fba_init(void)
 {
-       int ret;
-
        ASCEBC(dasd_fba_discipline.ebcname, 4);
-
-       ret = ccw_driver_register(&dasd_fba_driver);
-       if (ret)
-               return ret;
-
-       dasd_generic_auto_online(&dasd_fba_driver);
-       return 0;
+       return ccw_driver_register(&dasd_fba_driver);
 }
 
 static void __exit
@@ -589,22 +575,3 @@ dasd_fba_cleanup(void)
 
 module_init(dasd_fba_init);
 module_exit(dasd_fba_cleanup);
-
-/*
- * 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: 1
- * tab-width: 8
- * End:
- */
index da1fa91fc01dd42a94cffe047459c9ffc6a00136..14c910baa5fe6160192b7c548d8921b829707eda 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_fba.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
index fce2835e7d19a5008427665b0ef9110e8c920e2a..61ffde718a7a84f881969d0b51a5a0cd394b4829 100644 (file)
@@ -68,8 +68,6 @@ dasd_gendisk_alloc(struct dasd_device *device)
        }
        len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
 
-       sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
-
        if (device->features & DASD_FEATURE_READONLY)
                set_disk_ro(gdp, 1);
        gdp->private_data = device;
index d4b13e300a76db523ad2f263ce2f55023c108e6e..3ccf06d28ba11ba2cc6b793c41317fd7c92d8758 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd_int.h
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst Hummel <Horst.Hummel@de.ibm.com> 
+ *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
@@ -54,7 +54,6 @@
 #include <linux/module.h>
 #include <linux/wait.h>
 #include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
@@ -186,7 +185,7 @@ struct dasd_ccw_req {
         void *callback_data;
 };
 
-/* 
+/*
  * dasd_ccw_req -> status can be:
  */
 #define DASD_CQR_FILLED   0x00 /* request is ready to be processed */
@@ -248,7 +247,7 @@ struct dasd_discipline {
         /*
          * Error recovery functions. examine_error() returns a value that
          * indicates what to do for an error condition. If examine_error()
-         * returns 'dasd_era_recover' erp_action() is called to create a 
+        * returns 'dasd_era_recover' erp_action() is called to create a
          * special error recovery ccw. erp_postaction() is called after
          * an error recovery ccw has finished its execution. dump_sense
          * is called for every error condition to print the sense data
@@ -302,11 +301,11 @@ struct dasd_device {
        spinlock_t request_queue_lock;
        struct block_device *bdev;
         unsigned int devindex;
-       unsigned long blocks;           /* size of volume in blocks */
-       unsigned int bp_block;          /* bytes per block */
-       unsigned int s2b_shift;         /* log2 (bp_block/512) */
-       unsigned long flags;            /* per device flags */
-       unsigned short features;        /* copy of devmap-features (read-only!) */
+       unsigned long blocks;      /* size of volume in blocks */
+       unsigned int bp_block;     /* bytes per block */
+       unsigned int s2b_shift;    /* log2 (bp_block/512) */
+       unsigned long flags;       /* per device flags */
+       unsigned short features;   /* copy of devmap-features (read-only!) */
 
        /* extended error reporting stuff (eer) */
        struct dasd_ccw_req *eer_cqr;
@@ -513,12 +512,12 @@ void dasd_generic_remove (struct ccw_device *cdev);
 int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
 int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
-void dasd_generic_auto_online (struct ccw_driver *);
 
 /* externals in dasd_devmap.c */
 extern int dasd_max_devindex;
 extern int dasd_probeonly;
 extern int dasd_autodetect;
+extern int dasd_nopav;
 
 int dasd_devmap_init(void);
 void dasd_devmap_exit(void);
@@ -606,22 +605,3 @@ static inline int dasd_eer_enabled(struct dasd_device *device)
 #endif                         /* __KERNEL__ */
 
 #endif                         /* DASD_H */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-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: 1
- * tab-width: 8
- * End:
- */
index b8c80d28df41dba762d8827608fd22e5c5c93e2f..302bcd0f28be4c4532862915417ba2a5add9ea2d 100644 (file)
@@ -90,10 +90,10 @@ static int
 dasd_ioctl_quiesce(struct dasd_device *device)
 {
        unsigned long flags;
-       
+
        if (!capable (CAP_SYS_ADMIN))
                return -EACCES;
-       
+
        DEV_MESSAGE (KERN_DEBUG, device, "%s",
                     "Quiesce IO on device");
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
@@ -110,13 +110,13 @@ static int
 dasd_ioctl_resume(struct dasd_device *device)
 {
        unsigned long flags;
-       
-       if (!capable (CAP_SYS_ADMIN)) 
+
+       if (!capable (CAP_SYS_ADMIN))
                return -EACCES;
 
        DEV_MESSAGE (KERN_DEBUG, device, "%s",
                     "resume IO on device");
-       
+
        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
        device->stopped &= ~DASD_STOPPED_QUIESCE;
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
@@ -287,7 +287,7 @@ dasd_ioctl_information(struct dasd_device *device,
        dasd_info->open_count = atomic_read(&device->open_count);
        if (!device->bdev)
                dasd_info->open_count++;
-       
+
        /*
         * check if device is really formatted
         * LDL / CDL was returned by 'fill_info'
index 54ecd548c3185b1aac9a78e7343b079bce771ea9..4c1e56b9b98dbaafa5b85cc6d74138489112248f 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/hdreg.h>  /* HDIO_GETGEO */
 #include <linux/sysdev.h>
 #include <linux/bio.h>
-#include <linux/devfs_fs_kernel.h>
 #include <asm/uaccess.h>
 
 #define XPRAM_NAME     "xpram"
@@ -439,8 +438,6 @@ static int __init xpram_setup_blkdev(void)
        if (rc < 0)
                goto out;
 
-       devfs_mk_dir("slram");
-
        /*
         * Assign the other needed values: make request function, sizes and
         * hardsect size. All the minor devices feature the same value.
@@ -469,14 +466,12 @@ static int __init xpram_setup_blkdev(void)
                disk->private_data = &xpram_devices[i];
                disk->queue = xpram_queue;
                sprintf(disk->disk_name, "slram%d", i);
-               sprintf(disk->devfs_name, "slram/%d", i);
                set_capacity(disk, xpram_sizes[i] << 1);
                add_disk(disk);
        }
 
        return 0;
 out_unreg:
-       devfs_remove("slram");
        unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
 out:
        while (i--)
@@ -495,7 +490,6 @@ static void __exit xpram_exit(void)
                put_disk(xpram_disks[i]);
        }
        unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
-       devfs_remove("slram");
        blk_cleanup_queue(xpram_queue);
        sysdev_unregister(&xpram_sys_device);
        sysdev_class_unregister(&xpram_sysclass);
index fb7bc9e5eebc90a20c09ae40f07b3df2a4c3e950..a138b1510093cc53a6538a99c47fe020da53518a 100644 (file)
@@ -586,7 +586,6 @@ static struct file_operations mon_fops = {
 
 static struct miscdevice mon_dev = {
        .name       = "monreader",
-       .devfs_name = "monreader",
        .fops       = &mon_fops,
        .minor      = MISC_DYNAMIC_MINOR,
 };
index eecb2afad5c25ce460acdeba66041b7d5f291838..3c1314b7391b0fe5141982210c366dfb902875e0 100644 (file)
@@ -50,6 +50,9 @@ struct raw3270 {
        unsigned char *ascebc;          /* ascii -> ebcdic table */
        struct class_device *clttydev;  /* 3270-class tty device ptr */
        struct class_device *cltubdev;  /* 3270-class tub device ptr */
+
+       struct raw3270_request init_request;
+       unsigned char init_data[256];
 };
 
 /* raw3270->flags */
@@ -484,8 +487,6 @@ struct raw3270_ua { /* Query Reply structure for Usable Area */
        } __attribute__ ((packed)) aua;
 } __attribute__ ((packed));
 
-static unsigned char raw3270_init_data[256];
-static struct raw3270_request raw3270_init_request;
 static struct diag210 raw3270_init_diag210;
 static DECLARE_MUTEX(raw3270_init_sem);
 
@@ -644,17 +645,17 @@ __raw3270_size_device(struct raw3270 *rp)
         * required (3270 device switched to 'stand-by') and command
         * rejects (old devices that can't do 'read partition').
         */
-       memset(&raw3270_init_request, 0, sizeof(raw3270_init_request));
-       memset(raw3270_init_data, 0, sizeof(raw3270_init_data));
-       /* Store 'read partition' data stream to raw3270_init_data */
-       memcpy(raw3270_init_data, wbuf, sizeof(wbuf));
-       INIT_LIST_HEAD(&raw3270_init_request.list);
-       raw3270_init_request.ccw.cmd_code = TC_WRITESF;
-       raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
-       raw3270_init_request.ccw.count = sizeof(wbuf);
-       raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
-
-       rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+       memset(&rp->init_request, 0, sizeof(rp->init_request));
+       memset(&rp->init_data, 0, 256);
+       /* Store 'read partition' data stream to init_data */
+       memcpy(&rp->init_data, wbuf, sizeof(wbuf));
+       INIT_LIST_HEAD(&rp->init_request.list);
+       rp->init_request.ccw.cmd_code = TC_WRITESF;
+       rp->init_request.ccw.flags = CCW_FLAG_SLI;
+       rp->init_request.ccw.count = sizeof(wbuf);
+       rp->init_request.ccw.cda = (__u32) __pa(&rp->init_data);
+
+       rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
        if (rc)
                /* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
                return rc;
@@ -679,18 +680,18 @@ __raw3270_size_device(struct raw3270 *rp)
         * The device accepted the 'read partition' command. Now
         * set up a read ccw and issue it.
         */
-       raw3270_init_request.ccw.cmd_code = TC_READMOD;
-       raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
-       raw3270_init_request.ccw.count = sizeof(raw3270_init_data);
-       raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
-       rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+       rp->init_request.ccw.cmd_code = TC_READMOD;
+       rp->init_request.ccw.flags = CCW_FLAG_SLI;
+       rp->init_request.ccw.count = sizeof(rp->init_data);
+       rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
+       rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
        if (rc)
                return rc;
        /* Got a Query Reply */
-       count = sizeof(raw3270_init_data) - raw3270_init_request.rescnt;
-       uap = (struct raw3270_ua *) (raw3270_init_data + 1);
+       count = sizeof(rp->init_data) - rp->init_request.rescnt;
+       uap = (struct raw3270_ua *) (rp->init_data + 1);
        /* Paranoia check. */
-       if (raw3270_init_data[0] != 0x88 || uap->uab.qcode != 0x81)
+       if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
                return -EOPNOTSUPP;
        /* Copy rows/columns of default Usable Area */
        rp->rows = uap->uab.h;
@@ -749,18 +750,18 @@ raw3270_reset_device(struct raw3270 *rp)
        int rc;
 
        down(&raw3270_init_sem);
-       memset(&raw3270_init_request, 0, sizeof(raw3270_init_request));
-       memset(raw3270_init_data, 0, sizeof(raw3270_init_data));
-       /* Store reset data stream to raw3270_init_data/raw3270_init_request */
-       raw3270_init_data[0] = TW_KR;
-       INIT_LIST_HEAD(&raw3270_init_request.list);
-       raw3270_init_request.ccw.cmd_code = TC_EWRITEA;
-       raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
-       raw3270_init_request.ccw.count = 1;
-       raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
+       memset(&rp->init_request, 0, sizeof(rp->init_request));
+       memset(&rp->init_data, 0, sizeof(rp->init_data));
+       /* Store reset data stream to init_data/init_request */
+       rp->init_data[0] = TW_KR;
+       INIT_LIST_HEAD(&rp->init_request.list);
+       rp->init_request.ccw.cmd_code = TC_EWRITEA;
+       rp->init_request.ccw.flags = CCW_FLAG_SLI;
+       rp->init_request.ccw.count = 1;
+       rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
        rp->view = &raw3270_init_view;
        raw3270_init_view.dev = rp;
-       rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+       rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
        raw3270_init_view.dev = 0;
        rp->view = 0;
        up(&raw3270_init_sem);
@@ -854,7 +855,7 @@ raw3270_setup_console(struct ccw_device *cdev)
        char *ascebc;
        int rc;
 
-       rp = (struct raw3270 *) alloc_bootmem(sizeof(struct raw3270));
+       rp = (struct raw3270 *) alloc_bootmem_low(sizeof(struct raw3270));
        ascebc = (char *) alloc_bootmem(256);
        rc = raw3270_setup_device(cdev, rp, ascebc);
        if (rc)
@@ -895,7 +896,7 @@ raw3270_create_device(struct ccw_device *cdev)
        char *ascebc;
        int rc;
 
-       rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL);
+       rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
        if (!rp)
                return ERR_PTR(-ENOMEM);
        ascebc = kmalloc(256, GFP_KERNEL);
index 9a141776873fc42de018fb59f1cb8a681819a6e5..7d26a3e4cb80797f10256e5de65f389f619cd960 100644 (file)
@@ -1785,7 +1785,6 @@ tty3270_init(void)
         * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
         */
        driver->owner = THIS_MODULE;
-       driver->devfs_name = "ttyTUB/";
        driver->driver_name = "ttyTUB";
        driver->name = "ttyTUB";
        driver->major = IBM_TTY3270_MAJOR;
@@ -1793,7 +1792,7 @@ tty3270_init(void)
        driver->type = TTY_DRIVER_TYPE_SYSTEM;
        driver->subtype = SYSTEM_TYPE_TTY;
        driver->init_termios = tty_std_termios;
-       driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
+       driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV;
        tty_set_operations(driver, &tty3270_ops);
        ret = tty_register_driver(driver);
        if (ret) {
index 0960bef7b199ca6c45868f6e746dee1a862550ac..15b895496a45025038559b18eb874d1b6b6cfc50 100644 (file)
@@ -224,39 +224,6 @@ is_blacklisted (int ssid, int devno)
 }
 
 #ifdef CONFIG_PROC_FS
-static int
-__s390_redo_validation(struct subchannel_id schid, void *data)
-{
-       int ret;
-       struct subchannel *sch;
-
-       sch = get_subchannel_by_schid(schid);
-       if (sch) {
-               /* Already known. */
-               put_device(&sch->dev);
-               return 0;
-       }
-       ret = css_probe_device(schid);
-       if (ret == -ENXIO)
-               return ret; /* We're through. */
-       if (ret == -ENOMEM)
-               /* Stop validation for now. Bad, but no need for a panic. */
-               return ret;
-       return 0;
-}
-
-/*
- * Function: s390_redo_validation
- * Look for no longer blacklisted devices
- * FIXME: there must be a better way to do this */
-static inline void
-s390_redo_validation (void)
-{
-       CIO_TRACE_EVENT (0, "redoval");
-
-       for_each_subchannel(__s390_redo_validation, NULL);
-}
-
 /*
  * Function: blacklist_parse_proc_parameters
  * parse the stuff which is piped to /proc/cio_ignore
@@ -281,7 +248,7 @@ blacklist_parse_proc_parameters (char *buf)
                return;
        }
 
-       s390_redo_validation ();
+       css_schedule_reprobe();
 }
 
 /* Iterator struct for all devices. */
index bdfee7fbaa2ea1f4f9af9e6c964ef04c52f6cd09..c7319a07ba35161fde79dac21de10332d0387736 100644 (file)
@@ -404,21 +404,24 @@ ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
 }
 
 static int
-__ccwgroup_driver_unregister_device(struct device *dev, void *data)
+__ccwgroup_match_all(struct device *dev, void *data)
 {
-       __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
-       device_unregister(dev);
-       put_device(dev);
-       return 0;
+       return 1;
 }
 
 void
 ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
 {
+       struct device *dev;
+
        /* We don't want ccwgroup devices to live longer than their driver. */
        get_driver(&cdriver->driver);
-       driver_for_each_device(&cdriver->driver, NULL, NULL,
-                              __ccwgroup_driver_unregister_device);
+       while ((dev = driver_find_device(&cdriver->driver, NULL, NULL,
+                                        __ccwgroup_match_all))) {
+               __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
+               device_unregister(dev);
+               put_device(dev);
+       }
        put_driver(&cdriver->driver);
        driver_unregister(&cdriver->driver);
 }
index 72187e54dcac79353107616bac3fb1aec3f1b4d0..b00f3ed051a094bf259d90b62026959ad139143c 100644 (file)
@@ -244,8 +244,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
 
        if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) &&
            (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) &&
-           (sch->schib.pmcw.lpum == mask) &&
-           (sch->vpm == 0)) {
+           (sch->schib.pmcw.lpum == mask)) {
                int cc;
 
                cc = cio_clear(sch);
@@ -918,12 +917,13 @@ chp_measurement_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
        chp = to_channelpath(container_of(kobj, struct device, kobj));
        css = to_css(chp->dev.parent);
 
-       size = sizeof(struct cmg_chars);
+       size = sizeof(struct cmg_entry);
 
        /* Only allow single reads. */
        if (off || count < size)
                return 0;
        chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->id);
+       count = size;
        return count;
 }
 
index 07ef3f640f4aa73ec17460a93ab020f21a9bfb2e..1c3e8e9012b08c3553c1b5b7de806a87598f2fc0 100644 (file)
@@ -3,9 +3,10 @@
  *
  * Linux on zSeries Channel Measurement Facility support
  *
- * Copyright 2000,2003 IBM Corporation
+ * Copyright 2000,2006 IBM Corporation
  *
- * Author: Arnd Bergmann <arndb@de.ibm.com>
+ * Authors: Arnd Bergmann <arndb@de.ibm.com>
+ *         Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  * original idea from Natarajan Krishnaswami <nkrishna@us.ibm.com>
  *
@@ -96,9 +97,9 @@ module_param(format, bool, 0444);
 /**
  * struct cmb_operations - functions to use depending on cmb_format
  *
- * all these functions operate on a struct cmf_device. There is only
- * one instance of struct cmb_operations because all cmf_device
- * objects are guaranteed to be of the same type.
+ * Most of these functions operate on a struct ccw_device. There is only
+ * one instance of struct cmb_operations because the format of the measurement
+ * data is guaranteed to be the same for every ccw_device.
  *
  * @alloc:     allocate memory for a channel measurement block,
  *             either with the help of a special pool or with kmalloc
@@ -107,6 +108,7 @@ module_param(format, bool, 0444);
  * @readall:   read a measurement block in a common format
  * @reset:     clear the data in the associated measurement block and
  *             reset its time stamp
+ * @align:     align an allocated block so that the hardware can use it
  */
 struct cmb_operations {
        int (*alloc)  (struct ccw_device*);
@@ -115,11 +117,19 @@ struct cmb_operations {
        u64 (*read)   (struct ccw_device*, int);
        int (*readall)(struct ccw_device*, struct cmbdata *);
        void (*reset) (struct ccw_device*);
+       void * (*align) (void *);
 
        struct attribute_group *attr_group;
 };
 static struct cmb_operations *cmbops;
 
+struct cmb_data {
+       void *hw_block;   /* Pointer to block updated by hardware */
+       void *last_block; /* Last changed block copied from hardware block */
+       int size;         /* Size of hw_block and last_block */
+       unsigned long long last_update;  /* when last_block was updated */
+};
+
 /* our user interface is designed in terms of nanoseconds,
  * while the hardware measures total times in its own
  * unit.*/
@@ -226,63 +236,229 @@ struct set_schib_struct {
        unsigned long address;
        wait_queue_head_t wait;
        int ret;
+       struct kref kref;
 };
 
+static void cmf_set_schib_release(struct kref *kref)
+{
+       struct set_schib_struct *set_data;
+
+       set_data = container_of(kref, struct set_schib_struct, kref);
+       kfree(set_data);
+}
+
+#define CMF_PENDING 1
+
 static int set_schib_wait(struct ccw_device *cdev, u32 mme,
                                int mbfc, unsigned long address)
 {
-       struct set_schib_struct s = {
-               .mme = mme,
-               .mbfc = mbfc,
-               .address = address,
-               .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s.wait),
-       };
+       struct set_schib_struct *set_data;
+       int ret;
 
        spin_lock_irq(cdev->ccwlock);
-       s.ret = set_schib(cdev, mme, mbfc, address);
-       if (s.ret != -EBUSY) {
-               goto out_nowait;
+       if (!cdev->private->cmb) {
+               ret = -ENODEV;
+               goto out;
        }
+       set_data = kzalloc(sizeof(struct set_schib_struct), GFP_ATOMIC);
+       if (!set_data) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       init_waitqueue_head(&set_data->wait);
+       kref_init(&set_data->kref);
+       set_data->mme = mme;
+       set_data->mbfc = mbfc;
+       set_data->address = address;
+
+       ret = set_schib(cdev, mme, mbfc, address);
+       if (ret != -EBUSY)
+               goto out_put;
 
        if (cdev->private->state != DEV_STATE_ONLINE) {
-               s.ret = -EBUSY;
                /* if the device is not online, don't even try again */
-               goto out_nowait;
+               ret = -EBUSY;
+               goto out_put;
        }
+
        cdev->private->state = DEV_STATE_CMFCHANGE;
-       cdev->private->cmb_wait = &s;
-       s.ret = 1;
+       set_data->ret = CMF_PENDING;
+       cdev->private->cmb_wait = set_data;
 
        spin_unlock_irq(cdev->ccwlock);
-       if (wait_event_interruptible(s.wait, s.ret != 1)) {
+       if (wait_event_interruptible(set_data->wait,
+                                    set_data->ret != CMF_PENDING)) {
                spin_lock_irq(cdev->ccwlock);
-               if (s.ret == 1) {
-                       s.ret = -ERESTARTSYS;
-                       cdev->private->cmb_wait = 0;
+               if (set_data->ret == CMF_PENDING) {
+                       set_data->ret = -ERESTARTSYS;
                        if (cdev->private->state == DEV_STATE_CMFCHANGE)
                                cdev->private->state = DEV_STATE_ONLINE;
                }
                spin_unlock_irq(cdev->ccwlock);
        }
-       return s.ret;
-
-out_nowait:
+       spin_lock_irq(cdev->ccwlock);
+       cdev->private->cmb_wait = NULL;
+       ret = set_data->ret;
+out_put:
+       kref_put(&set_data->kref, cmf_set_schib_release);
+out:
        spin_unlock_irq(cdev->ccwlock);
-       return s.ret;
+       return ret;
 }
 
 void retry_set_schib(struct ccw_device *cdev)
 {
-       struct set_schib_struct *s;
+       struct set_schib_struct *set_data;
+
+       set_data = cdev->private->cmb_wait;
+       if (!set_data) {
+               WARN_ON(1);
+               return;
+       }
+       kref_get(&set_data->kref);
+       set_data->ret = set_schib(cdev, set_data->mme, set_data->mbfc,
+                                 set_data->address);
+       wake_up(&set_data->wait);
+       kref_put(&set_data->kref, cmf_set_schib_release);
+}
+
+static int cmf_copy_block(struct ccw_device *cdev)
+{
+       struct subchannel *sch;
+       void *reference_buf;
+       void *hw_block;
+       struct cmb_data *cmb_data;
+
+       sch = to_subchannel(cdev->dev.parent);
+
+       if (stsch(sch->schid, &sch->schib))
+               return -ENODEV;
+
+       if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) {
+               /* Don't copy if a start function is in progress. */
+               if ((!sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED) &&
+                   (sch->schib.scsw.actl &
+                    (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) &&
+                   (!sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS))
+                       return -EBUSY;
+       }
+       cmb_data = cdev->private->cmb;
+       hw_block = cmbops->align(cmb_data->hw_block);
+       if (!memcmp(cmb_data->last_block, hw_block, cmb_data->size))
+               /* No need to copy. */
+               return 0;
+       reference_buf = kzalloc(cmb_data->size, GFP_ATOMIC);
+       if (!reference_buf)
+               return -ENOMEM;
+       /* Ensure consistency of block copied from hardware. */
+       do {
+               memcpy(cmb_data->last_block, hw_block, cmb_data->size);
+               memcpy(reference_buf, hw_block, cmb_data->size);
+       } while (memcmp(cmb_data->last_block, reference_buf, cmb_data->size));
+       cmb_data->last_update = get_clock();
+       kfree(reference_buf);
+       return 0;
+}
+
+struct copy_block_struct {
+       wait_queue_head_t wait;
+       int ret;
+       struct kref kref;
+};
+
+static void cmf_copy_block_release(struct kref *kref)
+{
+       struct copy_block_struct *copy_block;
+
+       copy_block = container_of(kref, struct copy_block_struct, kref);
+       kfree(copy_block);
+}
+
+static int cmf_cmb_copy_wait(struct ccw_device *cdev)
+{
+       struct copy_block_struct *copy_block;
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       if (!cdev->private->cmb) {
+               ret = -ENODEV;
+               goto out;
+       }
+       copy_block = kzalloc(sizeof(struct copy_block_struct), GFP_ATOMIC);
+       if (!copy_block) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       init_waitqueue_head(&copy_block->wait);
+       kref_init(&copy_block->kref);
+
+       ret = cmf_copy_block(cdev);
+       if (ret != -EBUSY)
+               goto out_put;
+
+       if (cdev->private->state != DEV_STATE_ONLINE) {
+               ret = -EBUSY;
+               goto out_put;
+       }
+
+       cdev->private->state = DEV_STATE_CMFUPDATE;
+       copy_block->ret = CMF_PENDING;
+       cdev->private->cmb_wait = copy_block;
+
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       if (wait_event_interruptible(copy_block->wait,
+                                    copy_block->ret != CMF_PENDING)) {
+               spin_lock_irqsave(cdev->ccwlock, flags);
+               if (copy_block->ret == CMF_PENDING) {
+                       copy_block->ret = -ERESTARTSYS;
+                       if (cdev->private->state == DEV_STATE_CMFUPDATE)
+                               cdev->private->state = DEV_STATE_ONLINE;
+               }
+               spin_unlock_irqrestore(cdev->ccwlock, flags);
+       }
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       cdev->private->cmb_wait = NULL;
+       ret = copy_block->ret;
+out_put:
+       kref_put(&copy_block->kref, cmf_copy_block_release);
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
+}
+
+void cmf_retry_copy_block(struct ccw_device *cdev)
+{
+       struct copy_block_struct *copy_block;
 
-       s = cdev->private->cmb_wait;
-       cdev->private->cmb_wait = 0;
-       if (!s) {
+       copy_block = cdev->private->cmb_wait;
+       if (!copy_block) {
                WARN_ON(1);
                return;
        }
-       s->ret = set_schib(cdev, s->mme, s->mbfc, s->address);
-       wake_up(&s->wait);
+       kref_get(&copy_block->kref);
+       copy_block->ret = cmf_copy_block(cdev);
+       wake_up(&copy_block->wait);
+       kref_put(&copy_block->kref, cmf_copy_block_release);
+}
+
+static void cmf_generic_reset(struct ccw_device *cdev)
+{
+       struct cmb_data *cmb_data;
+
+       spin_lock_irq(cdev->ccwlock);
+       cmb_data = cdev->private->cmb;
+       if (cmb_data) {
+               memset(cmb_data->last_block, 0, cmb_data->size);
+               /*
+                * Need to reset hw block as well to make the hardware start
+                * from 0 again.
+                */
+               memset(cmbops->align(cmb_data->hw_block), 0, cmb_data->size);
+               cmb_data->last_update = 0;
+       }
+       cdev->private->cmb_start_time = get_clock();
+       spin_unlock_irq(cdev->ccwlock);
 }
 
 /**
@@ -343,8 +519,8 @@ struct cmb {
 /* insert a single device into the cmb_area list
  * called with cmb_area.lock held from alloc_cmb
  */
-static inline int
-alloc_cmb_single (struct ccw_device *cdev)
+static inline int alloc_cmb_single (struct ccw_device *cdev,
+                                   struct cmb_data *cmb_data)
 {
        struct cmb *cmb;
        struct ccw_device_private *node;
@@ -358,10 +534,12 @@ alloc_cmb_single (struct ccw_device *cdev)
 
        /* find first unused cmb in cmb_area.mem.
         * this is a little tricky: cmb_area.list
-        * remains sorted by ->cmb pointers */
+        * remains sorted by ->cmb->hw_data pointers */
        cmb = cmb_area.mem;
        list_for_each_entry(node, &cmb_area.list, cmb_list) {
-               if ((struct cmb*)node->cmb > cmb)
+               struct cmb_data *data;
+               data = node->cmb;
+               if ((struct cmb*)data->hw_block > cmb)
                        break;
                cmb++;
        }
@@ -372,7 +550,8 @@ alloc_cmb_single (struct ccw_device *cdev)
 
        /* insert new cmb */
        list_add_tail(&cdev->private->cmb_list, &node->cmb_list);
-       cdev->private->cmb = cmb;
+       cmb_data->hw_block = cmb;
+       cdev->private->cmb = cmb_data;
        ret = 0;
 out:
        spin_unlock_irq(cdev->ccwlock);
@@ -385,7 +564,19 @@ alloc_cmb (struct ccw_device *cdev)
        int ret;
        struct cmb *mem;
        ssize_t size;
+       struct cmb_data *cmb_data;
+
+       /* Allocate private cmb_data. */
+       cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
+       if (!cmb_data)
+               return -ENOMEM;
 
+       cmb_data->last_block = kzalloc(sizeof(struct cmb), GFP_KERNEL);
+       if (!cmb_data->last_block) {
+               kfree(cmb_data);
+               return -ENOMEM;
+       }
+       cmb_data->size = sizeof(struct cmb);
        spin_lock(&cmb_area.lock);
 
        if (!cmb_area.mem) {
@@ -414,29 +605,36 @@ alloc_cmb (struct ccw_device *cdev)
        }
 
        /* do the actual allocation */
-       ret = alloc_cmb_single(cdev);
+       ret = alloc_cmb_single(cdev, cmb_data);
 out:
        spin_unlock(&cmb_area.lock);
-
+       if (ret) {
+               kfree(cmb_data->last_block);
+               kfree(cmb_data);
+       }
        return ret;
 }
 
-static void
-free_cmb(struct ccw_device *cdev)
+static void free_cmb(struct ccw_device *cdev)
 {
        struct ccw_device_private *priv;
-
-       priv = cdev->private;
+       struct cmb_data *cmb_data;
 
        spin_lock(&cmb_area.lock);
        spin_lock_irq(cdev->ccwlock);
 
+       priv = cdev->private;
+
        if (list_empty(&priv->cmb_list)) {
                /* already freed */
                goto out;
        }
 
+       cmb_data = priv->cmb;
        priv->cmb = NULL;
+       if (cmb_data)
+               kfree(cmb_data->last_block);
+       kfree(cmb_data);
        list_del_init(&priv->cmb_list);
 
        if (list_empty(&cmb_area.list)) {
@@ -451,83 +649,97 @@ out:
        spin_unlock(&cmb_area.lock);
 }
 
-static int
-set_cmb(struct ccw_device *cdev, u32 mme)
+static int set_cmb(struct ccw_device *cdev, u32 mme)
 {
        u16 offset;
+       struct cmb_data *cmb_data;
+       unsigned long flags;
 
-       if (!cdev->private->cmb)
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       if (!cdev->private->cmb) {
+               spin_unlock_irqrestore(cdev->ccwlock, flags);
                return -EINVAL;
-
-       offset = mme ? (struct cmb *)cdev->private->cmb - cmb_area.mem : 0;
+       }
+       cmb_data = cdev->private->cmb;
+       offset = mme ? (struct cmb *)cmb_data->hw_block - cmb_area.mem : 0;
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
 
        return set_schib_wait(cdev, mme, 0, offset);
 }
 
-static u64
-read_cmb (struct ccw_device *cdev, int index)
+static u64 read_cmb (struct ccw_device *cdev, int index)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmb cmb;
-       unsigned long flags;
+       struct cmb *cmb;
        u32 val;
+       int ret;
+       unsigned long flags;
+
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
+               return 0;
 
        spin_lock_irqsave(cdev->ccwlock, flags);
        if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               return 0;
+               ret = 0;
+               goto out;
        }
-
-       cmb = *(struct cmb*)cdev->private->cmb;
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       cmb = ((struct cmb_data *)cdev->private->cmb)->last_block;
 
        switch (index) {
        case cmb_ssch_rsch_count:
-               return cmb.ssch_rsch_count;
+               ret = cmb->ssch_rsch_count;
+               goto out;
        case cmb_sample_count:
-               return cmb.sample_count;
+               ret = cmb->sample_count;
+               goto out;
        case cmb_device_connect_time:
-               val = cmb.device_connect_time;
+               val = cmb->device_connect_time;
                break;
        case cmb_function_pending_time:
-               val = cmb.function_pending_time;
+               val = cmb->function_pending_time;
                break;
        case cmb_device_disconnect_time:
-               val = cmb.device_disconnect_time;
+               val = cmb->device_disconnect_time;
                break;
        case cmb_control_unit_queuing_time:
-               val = cmb.control_unit_queuing_time;
+               val = cmb->control_unit_queuing_time;
                break;
        case cmb_device_active_only_time:
-               val = cmb.device_active_only_time;
+               val = cmb->device_active_only_time;
                break;
        default:
-               return 0;
+               ret = 0;
+               goto out;
        }
-       return time_to_avg_nsec(val, cmb.sample_count);
+       ret = time_to_avg_nsec(val, cmb->sample_count);
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
 }
 
-static int
-readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmb cmb;
-       unsigned long flags;
+       struct cmb *cmb;
+       struct cmb_data *cmb_data;
        u64 time;
+       unsigned long flags;
+       int ret;
 
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
+               return ret;
        spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               return -ENODEV;
+       cmb_data = cdev->private->cmb;
+       if (!cmb_data) {
+               ret = -ENODEV;
+               goto out;
        }
-
-       cmb = *(struct cmb*)cdev->private->cmb;
-       time = get_clock() - cdev->private->cmb_start_time;
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       if (cmb_data->last_update == 0) {
+               ret = -EAGAIN;
+               goto out;
+       }
+       cmb = cmb_data->last_block;
+       time = cmb_data->last_update - cdev->private->cmb_start_time;
 
        memset(data, 0, sizeof(struct cmbdata));
 
@@ -538,31 +750,32 @@ readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
        data->elapsed_time = (time * 1000) >> 12;
 
        /* copy data to new structure */
-       data->ssch_rsch_count = cmb.ssch_rsch_count;
-       data->sample_count = cmb.sample_count;
+       data->ssch_rsch_count = cmb->ssch_rsch_count;
+       data->sample_count = cmb->sample_count;
 
        /* time fields are converted to nanoseconds while copying */
-       data->device_connect_time = time_to_nsec(cmb.device_connect_time);
-       data->function_pending_time = time_to_nsec(cmb.function_pending_time);
-       data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time);
+       data->device_connect_time = time_to_nsec(cmb->device_connect_time);
+       data->function_pending_time = time_to_nsec(cmb->function_pending_time);
+       data->device_disconnect_time =
+               time_to_nsec(cmb->device_disconnect_time);
        data->control_unit_queuing_time
-               = time_to_nsec(cmb.control_unit_queuing_time);
+               = time_to_nsec(cmb->control_unit_queuing_time);
        data->device_active_only_time
-               = time_to_nsec(cmb.device_active_only_time);
+               = time_to_nsec(cmb->device_active_only_time);
+       ret = 0;
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
+}
 
-       return 0;
+static void reset_cmb(struct ccw_device *cdev)
+{
+       cmf_generic_reset(cdev);
 }
 
-static void
-reset_cmb(struct ccw_device *cdev)
+static void * align_cmb(void *area)
 {
-       struct cmb *cmb;
-       spin_lock_irq(cdev->ccwlock);
-       cmb = cdev->private->cmb;
-       if (cmb)
-               memset (cmb, 0, sizeof (*cmb));
-       cdev->private->cmb_start_time = get_clock();
-       spin_unlock_irq(cdev->ccwlock);
+       return area;
 }
 
 static struct attribute_group cmf_attr_group;
@@ -574,6 +787,7 @@ static struct cmb_operations cmbops_basic = {
        .read   = read_cmb,
        .readall    = readall_cmb,
        .reset      = reset_cmb,
+       .align      = align_cmb,
        .attr_group = &cmf_attr_group,
 };
 \f
@@ -610,22 +824,34 @@ static inline struct cmbe* cmbe_align(struct cmbe *c)
        return (struct cmbe*)addr;
 }
 
-static int
-alloc_cmbe (struct ccw_device *cdev)
+static int alloc_cmbe (struct ccw_device *cdev)
 {
        struct cmbe *cmbe;
-       cmbe = kmalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
+       struct cmb_data *cmb_data;
+       int ret;
+
+       cmbe = kzalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
        if (!cmbe)
                return -ENOMEM;
-
+       cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
+       if (!cmb_data) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       cmb_data->last_block = kzalloc(sizeof(struct cmbe), GFP_KERNEL);
+       if (!cmb_data->last_block) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       cmb_data->size = sizeof(struct cmbe);
        spin_lock_irq(cdev->ccwlock);
        if (cdev->private->cmb) {
-               kfree(cmbe);
                spin_unlock_irq(cdev->ccwlock);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out_free;
        }
-
-       cdev->private->cmb = cmbe;
+       cmb_data->hw_block = cmbe;
+       cdev->private->cmb = cmb_data;
        spin_unlock_irq(cdev->ccwlock);
 
        /* activate global measurement if this is the first channel */
@@ -636,14 +862,24 @@ alloc_cmbe (struct ccw_device *cdev)
        spin_unlock(&cmb_area.lock);
 
        return 0;
+out_free:
+       if (cmb_data)
+               kfree(cmb_data->last_block);
+       kfree(cmb_data);
+       kfree(cmbe);
+       return ret;
 }
 
-static void
-free_cmbe (struct ccw_device *cdev)
+static void free_cmbe (struct ccw_device *cdev)
 {
+       struct cmb_data *cmb_data;
+
        spin_lock_irq(cdev->ccwlock);
-       kfree(cdev->private->cmb);
+       cmb_data = cdev->private->cmb;
        cdev->private->cmb = NULL;
+       if (cmb_data)
+               kfree(cmb_data->last_block);
+       kfree(cmb_data);
        spin_unlock_irq(cdev->ccwlock);
 
        /* deactivate global measurement if this is the last channel */
@@ -654,89 +890,105 @@ free_cmbe (struct ccw_device *cdev)
        spin_unlock(&cmb_area.lock);
 }
 
-static int
-set_cmbe(struct ccw_device *cdev, u32 mme)
+static int set_cmbe(struct ccw_device *cdev, u32 mme)
 {
        unsigned long mba;
+       struct cmb_data *cmb_data;
+       unsigned long flags;
 
-       if (!cdev->private->cmb)
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       if (!cdev->private->cmb) {
+               spin_unlock_irqrestore(cdev->ccwlock, flags);
                return -EINVAL;
-       mba = mme ? (unsigned long) cmbe_align(cdev->private->cmb) : 0;
+       }
+       cmb_data = cdev->private->cmb;
+       mba = mme ? (unsigned long) cmbe_align(cmb_data->hw_block) : 0;
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
 
        return set_schib_wait(cdev, mme, 1, mba);
 }
 
 
-u64
-read_cmbe (struct ccw_device *cdev, int index)
+static u64 read_cmbe (struct ccw_device *cdev, int index)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmbe cmb;
-       unsigned long flags;
+       struct cmbe *cmb;
+       struct cmb_data *cmb_data;
        u32 val;
+       int ret;
+       unsigned long flags;
 
-       spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
                return 0;
-       }
 
-       cmb = *cmbe_align(cdev->private->cmb);
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       spin_lock_irqsave(cdev->ccwlock, flags);
+       cmb_data = cdev->private->cmb;
+       if (!cmb_data) {
+               ret = 0;
+               goto out;
+       }
+       cmb = cmb_data->last_block;
 
        switch (index) {
        case cmb_ssch_rsch_count:
-               return cmb.ssch_rsch_count;
+               ret = cmb->ssch_rsch_count;
+               goto out;
        case cmb_sample_count:
-               return cmb.sample_count;
+               ret = cmb->sample_count;
+               goto out;
        case cmb_device_connect_time:
-               val = cmb.device_connect_time;
+               val = cmb->device_connect_time;
                break;
        case cmb_function_pending_time:
-               val = cmb.function_pending_time;
+               val = cmb->function_pending_time;
                break;
        case cmb_device_disconnect_time:
-               val = cmb.device_disconnect_time;
+               val = cmb->device_disconnect_time;
                break;
        case cmb_control_unit_queuing_time:
-               val = cmb.control_unit_queuing_time;
+               val = cmb->control_unit_queuing_time;
                break;
        case cmb_device_active_only_time:
-               val = cmb.device_active_only_time;
+               val = cmb->device_active_only_time;
                break;
        case cmb_device_busy_time:
-               val = cmb.device_busy_time;
+               val = cmb->device_busy_time;
                break;
        case cmb_initial_command_response_time:
-               val = cmb.initial_command_response_time;
+               val = cmb->initial_command_response_time;
                break;
        default:
-               return 0;
+               ret = 0;
+               goto out;
        }
-       return time_to_avg_nsec(val, cmb.sample_count);
+       ret = time_to_avg_nsec(val, cmb->sample_count);
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
 }
 
-static int
-readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
 {
-       /* yes, we have to put it on the stack
-        * because the cmb must only be accessed
-        * atomically, e.g. with mvc */
-       struct cmbe cmb;
-       unsigned long flags;
+       struct cmbe *cmb;
+       struct cmb_data *cmb_data;
        u64 time;
+       unsigned long flags;
+       int ret;
 
+       ret = cmf_cmb_copy_wait(cdev);
+       if (ret < 0)
+               return ret;
        spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               return -ENODEV;
+       cmb_data = cdev->private->cmb;
+       if (!cmb_data) {
+               ret = -ENODEV;
+               goto out;
        }
-
-       cmb = *cmbe_align(cdev->private->cmb);
-       time = get_clock() - cdev->private->cmb_start_time;
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       if (cmb_data->last_update == 0) {
+               ret = -EAGAIN;
+               goto out;
+       }
+       time = cmb_data->last_update - cdev->private->cmb_start_time;
 
        memset (data, 0, sizeof(struct cmbdata));
 
@@ -746,35 +998,38 @@ readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
        /* conver to nanoseconds */
        data->elapsed_time = (time * 1000) >> 12;
 
+       cmb = cmb_data->last_block;
        /* copy data to new structure */
-       data->ssch_rsch_count = cmb.ssch_rsch_count;
-       data->sample_count = cmb.sample_count;
+       data->ssch_rsch_count = cmb->ssch_rsch_count;
+       data->sample_count = cmb->sample_count;
 
        /* time fields are converted to nanoseconds while copying */
-       data->device_connect_time = time_to_nsec(cmb.device_connect_time);
-       data->function_pending_time = time_to_nsec(cmb.function_pending_time);
-       data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time);
+       data->device_connect_time = time_to_nsec(cmb->device_connect_time);
+       data->function_pending_time = time_to_nsec(cmb->function_pending_time);
+       data->device_disconnect_time =
+               time_to_nsec(cmb->device_disconnect_time);
        data->control_unit_queuing_time
-               = time_to_nsec(cmb.control_unit_queuing_time);
+               = time_to_nsec(cmb->control_unit_queuing_time);
        data->device_active_only_time
-               = time_to_nsec(cmb.device_active_only_time);
-       data->device_busy_time = time_to_nsec(cmb.device_busy_time);
+               = time_to_nsec(cmb->device_active_only_time);
+       data->device_busy_time = time_to_nsec(cmb->device_busy_time);
        data->initial_command_response_time
-               = time_to_nsec(cmb.initial_command_response_time);
+               = time_to_nsec(cmb->initial_command_response_time);
 
-       return 0;
+       ret = 0;
+out:
+       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       return ret;
 }
 
-static void
-reset_cmbe(struct ccw_device *cdev)
+static void reset_cmbe(struct ccw_device *cdev)
 {
-       struct cmbe *cmb;
-       spin_lock_irq(cdev->ccwlock);
-       cmb = cmbe_align(cdev->private->cmb);
-       if (cmb)
-               memset (cmb, 0, sizeof (*cmb));
-       cdev->private->cmb_start_time = get_clock();
-       spin_unlock_irq(cdev->ccwlock);
+       cmf_generic_reset(cdev);
+}
+
+static void * align_cmbe(void *area)
+{
+       return cmbe_align(area);
 }
 
 static struct attribute_group cmf_attr_group_ext;
@@ -786,6 +1041,7 @@ static struct cmb_operations cmbops_extended = {
        .read       = read_cmbe,
        .readall    = readall_cmbe,
        .reset      = reset_cmbe,
+       .align      = align_cmbe,
        .attr_group = &cmf_attr_group_ext,
 };
 \f
@@ -803,14 +1059,19 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr,
        struct ccw_device *cdev;
        long interval;
        unsigned long count;
+       struct cmb_data *cmb_data;
 
        cdev = to_ccwdev(dev);
-       interval  = get_clock() - cdev->private->cmb_start_time;
        count = cmf_read(cdev, cmb_sample_count);
-       if (count)
+       spin_lock_irq(cdev->ccwlock);
+       cmb_data = cdev->private->cmb;
+       if (count) {
+               interval = cmb_data->last_update -
+                       cdev->private->cmb_start_time;
                interval /= count;
-       else
+       else
                interval = -1;
+       spin_unlock_irq(cdev->ccwlock);
        return sprintf(buf, "%ld\n", interval);
 }
 
@@ -823,7 +1084,10 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char
        int ret;
 
        ret = cmf_readall(to_ccwdev(dev), &data);
-       if (ret)
+       if (ret == -EAGAIN || ret == -ENODEV)
+               /* No data (yet/currently) available to use for calculation. */
+               return sprintf(buf, "n/a\n");
+       else if (ret)
                return ret;
 
        utilization = data.device_connect_time +
@@ -982,6 +1246,13 @@ cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
        return cmbops->readall(cdev, data);
 }
 
+/* Reenable cmf when a disconnected device becomes available again. */
+int cmf_reenable(struct ccw_device *cdev)
+{
+       cmbops->reset(cdev);
+       return cmbops->set(cdev, 2);
+}
+
 static int __init
 init_cmf(void)
 {
index 74ea8aac4b7d9683c37ce79e79a41edf673b9d07..1d3be80797f81e1ed119a08394f872cc20700236 100644 (file)
 #include "cio_debug.h"
 #include "ioasm.h"
 #include "chsc.h"
+#include "device.h"
 
 int need_rescan = 0;
 int css_init_done = 0;
+static int need_reprobe = 0;
 static int max_ssid = 0;
 
 struct channel_subsystem *css[__MAX_CSSID + 1];
@@ -339,6 +341,67 @@ typedef void (*workfunc)(void *);
 DECLARE_WORK(slow_path_work, (workfunc)css_trigger_slow_path, NULL);
 struct workqueue_struct *slow_path_wq;
 
+/* Reprobe subchannel if unregistered. */
+static int reprobe_subchannel(struct subchannel_id schid, void *data)
+{
+       struct subchannel *sch;
+       int ret;
+
+       CIO_DEBUG(KERN_INFO, 6, "cio: reprobe 0.%x.%04x\n",
+                 schid.ssid, schid.sch_no);
+       if (need_reprobe)
+               return -EAGAIN;
+
+       sch = get_subchannel_by_schid(schid);
+       if (sch) {
+               /* Already known. */
+               put_device(&sch->dev);
+               return 0;
+       }
+
+       ret = css_probe_device(schid);
+       switch (ret) {
+       case 0:
+               break;
+       case -ENXIO:
+       case -ENOMEM:
+               /* These should abort looping */
+               break;
+       default:
+               ret = 0;
+       }
+
+       return ret;
+}
+
+/* Work function used to reprobe all unregistered subchannels. */
+static void reprobe_all(void *data)
+{
+       int ret;
+
+       CIO_MSG_EVENT(2, "reprobe start\n");
+
+       need_reprobe = 0;
+       /* Make sure initial subchannel scan is done. */
+       wait_event(ccw_device_init_wq,
+                  atomic_read(&ccw_device_init_count) == 0);
+       ret = for_each_subchannel(reprobe_subchannel, NULL);
+
+       CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
+                     need_reprobe);
+}
+
+DECLARE_WORK(css_reprobe_work, reprobe_all, NULL);
+
+/* Schedule reprobing of all unregistered subchannels. */
+void css_schedule_reprobe(void)
+{
+       need_reprobe = 1;
+       queue_work(ccw_device_work, &css_reprobe_work);
+}
+
+EXPORT_SYMBOL_GPL(css_schedule_reprobe);
+
 /*
  * Rescan for new devices. FIXME: This is slow.
  * This function is called when we have lost CRWs due to overflows and we have
index 8e3053c2a451b4f5dc84d5b7fb77df52119d124c..eafde43e8410cd3e1f041343f86dad2bd543d8c6 100644 (file)
@@ -133,8 +133,8 @@ struct css_driver io_subchannel_driver = {
 
 struct workqueue_struct *ccw_device_work;
 struct workqueue_struct *ccw_device_notify_work;
-static wait_queue_head_t ccw_device_init_wq;
-static atomic_t ccw_device_init_count;
+wait_queue_head_t ccw_device_init_wq;
+atomic_t ccw_device_init_count;
 
 static int __init
 init_ccw_bus_type (void)
index 11587ebb72897dcd68d04dc8d26df767e01af52f..00be9a5b4acde18141a76d7aef38ad4b90b2347c 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef S390_DEVICE_H
 #define S390_DEVICE_H
 
+#include <asm/ccwdev.h>
+#include <asm/atomic.h>
+#include <linux/wait.h>
+
 /*
  * states of the device statemachine
  */
@@ -23,6 +27,7 @@ enum dev_state {
        DEV_STATE_DISCONNECTED,
        DEV_STATE_DISCONNECTED_SENSE_ID,
        DEV_STATE_CMFCHANGE,
+       DEV_STATE_CMFUPDATE,
        /* last element! */
        NR_DEV_STATES
 };
@@ -67,6 +72,8 @@ dev_fsm_final_state(struct ccw_device *cdev)
 
 extern struct workqueue_struct *ccw_device_work;
 extern struct workqueue_struct *ccw_device_notify_work;
+extern wait_queue_head_t ccw_device_init_wq;
+extern atomic_t ccw_device_init_count;
 
 void io_subchannel_recog_done(struct ccw_device *cdev);
 
@@ -112,5 +119,8 @@ int ccw_device_stlck(struct ccw_device *);
 void ccw_device_set_timeout(struct ccw_device *, int);
 extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
 
+/* Channel measurement facility related */
 void retry_set_schib(struct ccw_device *cdev);
+void cmf_retry_copy_block(struct ccw_device *);
+int cmf_reenable(struct ccw_device *);
 #endif
index 49ec562d7f60b7d9d5d3c7658851394c11020d8d..7d0dd72635ebde671ce882d13cab17ad6094019f 100644 (file)
@@ -336,8 +336,11 @@ ccw_device_oper_notify(void *data)
        if (!ret)
                /* Driver doesn't want device back. */
                ccw_device_do_unreg_rereg((void *)cdev);
-       else
+       else {
+               /* Reenable channel measurements, if needed. */
+               cmf_reenable(cdev);
                wake_up(&cdev->private->wait_q);
+       }
 }
 
 /*
@@ -861,6 +864,8 @@ ccw_device_clear_verify(struct ccw_device *cdev, enum dev_event dev_event)
        irb = (struct irb *) __LC_IRB;
        /* Accumulate status. We don't do basic sense. */
        ccw_device_accumulate_irb(cdev, irb);
+       /* Remember to clear irb to avoid residuals. */
+       memset(&cdev->private->irb, 0, sizeof(struct irb));
        /* Try to start delayed device verification. */
        ccw_device_online_verify(cdev, 0);
        /* Note: Don't call handler for cio initiated clear! */
@@ -1093,6 +1098,13 @@ ccw_device_change_cmfstate(struct ccw_device *cdev, enum dev_event dev_event)
        dev_fsm_event(cdev, dev_event);
 }
 
+static void ccw_device_update_cmfblock(struct ccw_device *cdev,
+                                      enum dev_event dev_event)
+{
+       cmf_retry_copy_block(cdev);
+       cdev->private->state = DEV_STATE_ONLINE;
+       dev_fsm_event(cdev, dev_event);
+}
 
 static void
 ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event)
@@ -1247,6 +1259,12 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_TIMEOUT]     = ccw_device_change_cmfstate,
                [DEV_EVENT_VERIFY]      = ccw_device_change_cmfstate,
        },
+       [DEV_STATE_CMFUPDATE] = {
+               [DEV_EVENT_NOTOPER]     = ccw_device_update_cmfblock,
+               [DEV_EVENT_INTERRUPT]   = ccw_device_update_cmfblock,
+               [DEV_EVENT_TIMEOUT]     = ccw_device_update_cmfblock,
+               [DEV_EVENT_VERIFY]      = ccw_device_update_cmfblock,
+       },
 };
 
 /*
index 795abb5a65ba122620517ff44b7164deceec0a50..b266ad8e14ff2623fc6e5cea70e04d9a4160435b 100644 (file)
@@ -78,7 +78,8 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
                return -ENODEV;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
-       if (cdev->private->state == DEV_STATE_VERIFY) {
+       if (cdev->private->state == DEV_STATE_VERIFY ||
+           cdev->private->state == DEV_STATE_CLEAR_VERIFY) {
                /* Remember to fake irb when finished. */
                if (!cdev->private->flags.fake_irb) {
                        cdev->private->flags.fake_irb = 1;
@@ -270,7 +271,8 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
                 * We didn't get channel end / device end. Check if path
                 * verification has been started; we can retry after it has
                 * finished. We also retry unit checks except for command reject
-                * or intervention required.
+                * or intervention required. Also check for long busy
+                * conditions.
                 */
                 if (cdev->private->flags.doverify ||
                         cdev->private->state == DEV_STATE_VERIFY)
@@ -279,6 +281,10 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
                     !(irb->ecw[0] &
                       (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
                         cdev->private->intparm = -EAGAIN;
+               else if ((irb->scsw.dstat & DEV_STAT_ATTENTION) &&
+                        (irb->scsw.dstat & DEV_STAT_DEV_END) &&
+                        (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP))
+                       cdev->private->intparm = -EAGAIN;
                 else
                         cdev->private->intparm = -EIO;
                         
index 982acc7303ea299c1566e8580b3027556941a516..b2f20ab8431a05c6c53ffe460e51696d720c00e0 100644 (file)
@@ -411,7 +411,6 @@ static struct miscdevice z90crypt_misc_device = {
        .minor      = Z90CRYPT_MINOR,
        .name       = DEV_NAME,
        .fops       = &z90crypt_fops,
-       .devfs_name = DEV_NAME
 };
 
 /**
index f99e55308b32df8625658de3f63c1fddf5010236..8dc75002acbea71b1788ed35d314b42dc0e70207 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/errno.h>
 #include <linux/workqueue.h>
 #include <linux/time.h>
+#include <linux/kthread.h>
 
 #include <asm/lowcore.h>
 
@@ -56,8 +57,6 @@ s390_collect_crw_info(void *param)
        unsigned int chain;
 
        sem = (struct semaphore *)param;
-       /* Set a nice name. */
-       daemonize("kmcheck");
 repeat:
        down_interruptible(sem);
        slow = 0;
@@ -516,7 +515,7 @@ arch_initcall(machine_check_init);
 static int __init
 machine_check_crw_init (void)
 {
-       kernel_thread(s390_collect_crw_info, &m_sem, CLONE_FS|CLONE_FILES);
+       kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
        ctl_set_bit(14, 28);    /* enable channel report MCH */
        return 0;
 }
index ccb20a6f5f36d7593b991d985cb8a478f704368f..385f4f768311500ea278ae379bf7a29b86d196c0 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <linux/major.h>
-#include <linux/devfs_fs_kernel.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -1031,11 +1030,6 @@ static int __init bpp_init(void)
                instances[idx].opened = 0;
                probeLptPort(idx);
        }
-       devfs_mk_dir("bpp");
-       for (idx = 0; idx < BPP_NO; idx++) {
-               devfs_mk_cdev(MKDEV(BPP_MAJOR, idx),
-                               S_IFCHR | S_IRUSR | S_IWUSR, "bpp/%d", idx);
-       }
 
        return 0;
 }
@@ -1044,9 +1038,6 @@ static void __exit bpp_cleanup(void)
 {
        unsigned idx;
 
-       for (idx = 0; idx < BPP_NO; idx++)
-               devfs_remove("bpp/%d", idx);
-       devfs_remove("bpp");
        unregister_chrdev(BPP_MAJOR, dev_name);
 
        for (idx = 0;  idx < BPP_NO; idx++) {
index 8045cd5e7cb3389041cdef112aac185f6d90b968..63941a259b927436f2f96e7589d8e8267e48ffa9 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _LINUX_VFC_H_
 #define _LINUX_VFC_H_
 
-#include <linux/devfs_fs_kernel.h>
-
 /*
  * The control register for the vfc is at offset 0x4000
  * The first field ram bank is located at offset 0x5000
index ddcd330b9e891a46291650b12d917f90923c5277..55b2b31bd7abbf0d2dbcde64af303c952b442821 100644 (file)
@@ -164,10 +164,6 @@ int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance)
                return -EINVAL;
        if (init_vfc_hw(dev))
                return -EIO;
-
-       devfs_mk_cdev(MKDEV(VFC_MAJOR, instance),
-                       S_IFCHR | S_IRUSR | S_IWUSR,
-                       "vfc/%d", instance);
        return 0;
 }
 
@@ -677,7 +673,6 @@ static int vfc_probe(void)
                kfree(vfc_dev_lst);
                return -EIO;
        }
-       devfs_mk_dir("vfc");
        instance = 0;
        for_all_sbusdev(sdev, sbus) {
                if (strcmp(sdev->prom_name, "vfc") == 0) {
@@ -717,7 +712,6 @@ static void deinit_vfc_device(struct vfc_dev *dev)
 {
        if(dev == NULL)
                return;
-       devfs_remove("vfc/%d", dev->instance);
        sbus_iounmap(dev->regs, sizeof(struct vfc_regs));
        kfree(dev);
 }
@@ -731,7 +725,6 @@ void cleanup_module(void)
        for (devp = vfc_dev_lst; *devp; devp++)
                deinit_vfc_device(*devp);
 
-       devfs_remove("vfc");
        kfree(vfc_dev_lst);
        return;
 }
index c84b02aec1f35fd819428ba91956900959264884..96a81cd17617aaa95fe7bad50875488182f65081 100644 (file)
@@ -501,7 +501,7 @@ config SCSI_ATA_PIIX
        tristate "Intel PIIX/ICH SATA support"
        depends on SCSI_SATA && PCI
        help
-         This option enables support for ICH5 Serial ATA.
+         This option enables support for ICH5/6/7/8 Serial ATA.
          If PATA support was enabled previously, this enables
          support for select Intel PIIX/ICH PATA host controllers.
 
index 4bb77f62b3b9bef9c6660b990c4ee838213fb3ae..f059467777183f0463d604eefb3860c3884a3d36 100644 (file)
@@ -48,7 +48,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "ahci"
-#define DRV_VERSION    "1.3"
+#define DRV_VERSION    "2.0"
 
 
 enum {
index 521b718763f6c9ab0f324f5f07294048836d495f..94b1261a259d934d5a5506e22f215fa3af0854e0 100644 (file)
@@ -93,7 +93,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "ata_piix"
-#define DRV_VERSION    "1.10"
+#define DRV_VERSION    "2.00"
 
 enum {
        PIIX_IOCFG              = 0x54, /* IDE I/O configuration register */
index 6c66877be2bffe069b7663fc756fb176ed092003..d1c1c30d123f36946d74cbd873ddad63d1902ae4 100644 (file)
@@ -88,6 +88,10 @@ int libata_fua = 0;
 module_param_named(fua, libata_fua, int, 0444);
 MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
 
+static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
+module_param(ata_probe_timeout, int, 0444);
+MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
@@ -777,11 +781,9 @@ void ata_std_dev_select (struct ata_port *ap, unsigned int device)
 void ata_dev_select(struct ata_port *ap, unsigned int device,
                           unsigned int wait, unsigned int can_sleep)
 {
-       if (ata_msg_probe(ap)) {
+       if (ata_msg_probe(ap))
                ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: "
-                               "device %u, wait %u\n",
-                               ap->id, device, wait);
-       }
+                               "device %u, wait %u\n", ap->id, device, wait);
 
        if (wait)
                ata_wait_idle(ap);
@@ -950,7 +952,8 @@ void ata_port_flush_task(struct ata_port *ap)
         */
        if (!cancel_delayed_work(&ap->port_task)) {
                if (ata_msg_ctl(ap))
-                       ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n", __FUNCTION__);
+                       ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
+                                       __FUNCTION__);
                flush_workqueue(ata_wq);
        }
 
@@ -1059,7 +1062,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
 
        spin_unlock_irqrestore(ap->lock, flags);
 
-       rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL);
+       rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
 
        ata_port_flush_task(ap);
 
@@ -1081,7 +1084,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
 
                        if (ata_msg_warn(ap))
                                ata_dev_printk(dev, KERN_WARNING,
-                                      "qc timeout (cmd 0x%x)\n", command);
+                                       "qc timeout (cmd 0x%x)\n", command);
                }
 
                spin_unlock_irqrestore(ap->lock, flags);
@@ -1093,9 +1096,9 @@ unsigned ata_exec_internal(struct ata_device *dev,
 
        if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
                if (ata_msg_warn(ap))
-                       ata_dev_printk(dev, KERN_WARNING, 
+                       ata_dev_printk(dev, KERN_WARNING,
                                "zero err_mask for failed "
-                              "internal command, assuming AC_ERR_OTHER\n");
+                               "internal command, assuming AC_ERR_OTHER\n");
                qc->err_mask |= AC_ERR_OTHER;
        }
 
@@ -1131,6 +1134,33 @@ unsigned ata_exec_internal(struct ata_device *dev,
        return err_mask;
 }
 
+/**
+ *     ata_do_simple_cmd - execute simple internal command
+ *     @dev: Device to which the command is sent
+ *     @cmd: Opcode to execute
+ *
+ *     Execute a 'simple' command, that only consists of the opcode
+ *     'cmd' itself, without filling any other registers
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     Zero on success, AC_ERR_* mask on failure
+ */
+unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
+{
+       struct ata_taskfile tf;
+
+       ata_tf_init(dev, &tf);
+
+       tf.command = cmd;
+       tf.flags |= ATA_TFLAG_DEVICE;
+       tf.protocol = ATA_PROT_NODATA;
+
+       return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+}
+
 /**
  *     ata_pio_need_iordy      -       check if iordy needed
  *     @adev: ATA device
@@ -1193,8 +1223,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
        int rc;
 
        if (ata_msg_ctl(ap))
-               ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", 
-                               __FUNCTION__, ap->id, dev->devno);
+               ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+                              __FUNCTION__, ap->id, dev->devno);
 
        ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
 
@@ -1263,9 +1293,9 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
        return 0;
 
  err_out:
-       if (ata_msg_warn(ap)) 
+       if (ata_msg_warn(ap))
                ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
-                      "(%s, err_mask=0x%x)\n", reason, err_mask);
+                              "(%s, err_mask=0x%x)\n", reason, err_mask);
        return rc;
 }
 
@@ -1318,19 +1348,21 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
        int i, rc;
 
        if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
-               ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
-                       __FUNCTION__, ap->id, dev->devno);
+               ata_dev_printk(dev, KERN_INFO,
+                              "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
+                              __FUNCTION__, ap->id, dev->devno);
                return 0;
        }
 
        if (ata_msg_probe(ap))
-               ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", 
-                       __FUNCTION__, ap->id, dev->devno);
+               ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+                              __FUNCTION__, ap->id, dev->devno);
 
        /* print device capabilities */
        if (ata_msg_probe(ap))
-               ata_dev_printk(dev, KERN_DEBUG, "%s: cfg 49:%04x 82:%04x 83:%04x "
-                              "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+               ata_dev_printk(dev, KERN_DEBUG,
+                              "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x "
+                              "85:%04x 86:%04x 87:%04x 88:%04x\n",
                               __FUNCTION__,
                               id[49], id[82], id[83], id[84],
                               id[85], id[86], id[87], id[88]);
@@ -1402,14 +1434,16 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                                        ata_id_major_version(id),
                                        ata_mode_string(xfer_mask),
                                        (unsigned long long)dev->n_sectors,
-                                       dev->cylinders, dev->heads, dev->sectors);
+                                       dev->cylinders, dev->heads,
+                                       dev->sectors);
                }
 
                if (dev->id[59] & 0x100) {
                        dev->multi_count = dev->id[59] & 0xff;
                        if (ata_msg_info(ap))
-                               ata_dev_printk(dev, KERN_INFO, "ata%u: dev %u multi count %u\n",
-                               ap->id, dev->devno, dev->multi_count);
+                               ata_dev_printk(dev, KERN_INFO,
+                                       "ata%u: dev %u multi count %u\n",
+                                       ap->id, dev->devno, dev->multi_count);
                }
 
                dev->cdb_len = 16;
@@ -1422,8 +1456,8 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                rc = atapi_cdb_len(id);
                if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
                        if (ata_msg_warn(ap))
-                               ata_dev_printk(dev, KERN_WARNING, 
-                                       "unsupported CDB len\n");
+                               ata_dev_printk(dev, KERN_WARNING,
+                                              "unsupported CDB len\n");
                        rc = -EINVAL;
                        goto err_out_nosup;
                }
@@ -1466,8 +1500,8 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
 
 err_out_nosup:
        if (ata_msg_probe(ap))
-               ata_dev_printk(dev, KERN_DEBUG, 
-                               "%s: EXIT, err\n", __FUNCTION__);
+               ata_dev_printk(dev, KERN_DEBUG,
+                              "%s: EXIT, err\n", __FUNCTION__);
        return rc;
 }
 
@@ -3527,7 +3561,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
  *     Inherited from caller.
  */
 
-void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, 
+void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
                        unsigned int buflen, int write_data)
 {
        struct ata_port *ap = adev->ap;
@@ -3573,7 +3607,7 @@ void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
  *     Inherited from caller.
  */
 
-void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, 
+void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
                       unsigned int buflen, int write_data)
 {
        struct ata_port *ap = adev->ap;
@@ -3607,7 +3641,7 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
  *     @buflen: buffer length
  *     @write_data: read/write
  *
- *     Transfer data from/to the device data register by PIO. Do the 
+ *     Transfer data from/to the device data register by PIO. Do the
  *     transfer with interrupts disabled.
  *
  *     LOCKING:
@@ -4946,31 +4980,9 @@ int ata_port_offline(struct ata_port *ap)
        return 0;
 }
 
-/*
- * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
- * without filling any other registers
- */
-static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
-{
-       struct ata_taskfile tf;
-       int err;
-
-       ata_tf_init(dev, &tf);
-
-       tf.command = cmd;
-       tf.flags |= ATA_TFLAG_DEVICE;
-       tf.protocol = ATA_PROT_NODATA;
-
-       err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-       if (err)
-               ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n",
-                              __FUNCTION__, err);
-
-       return err;
-}
-
-static int ata_flush_cache(struct ata_device *dev)
+int ata_flush_cache(struct ata_device *dev)
 {
+       unsigned int err_mask;
        u8 cmd;
 
        if (!ata_try_flush_cache(dev))
@@ -4981,17 +4993,41 @@ static int ata_flush_cache(struct ata_device *dev)
        else
                cmd = ATA_CMD_FLUSH;
 
-       return ata_do_simple_cmd(dev, cmd);
+       err_mask = ata_do_simple_cmd(dev, cmd);
+       if (err_mask) {
+               ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
+               return -EIO;
+       }
+
+       return 0;
 }
 
 static int ata_standby_drive(struct ata_device *dev)
 {
-       return ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+       unsigned int err_mask;
+
+       err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+       if (err_mask) {
+               ata_dev_printk(dev, KERN_ERR, "failed to standby drive "
+                              "(err_mask=0x%x)\n", err_mask);
+               return -EIO;
+       }
+
+       return 0;
 }
 
 static int ata_start_drive(struct ata_device *dev)
 {
-       return ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
+       unsigned int err_mask;
+
+       err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
+       if (err_mask) {
+               ata_dev_printk(dev, KERN_ERR, "failed to start drive "
+                              "(err_mask=0x%x)\n", err_mask);
+               return -EIO;
+       }
+
+       return 0;
 }
 
 /**
@@ -5212,7 +5248,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
        ap->msg_enable = 0x00FF;
 #elif defined(ATA_DEBUG)
        ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR;
-#else 
+#else
        ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
 #endif
 
@@ -5709,6 +5745,7 @@ int ata_pci_device_resume(struct pci_dev *pdev)
 
 static int __init ata_init(void)
 {
+       ata_probe_timeout *= HZ;
        ata_wq = create_workqueue("ata");
        if (!ata_wq)
                return -ENOMEM;
@@ -5733,7 +5770,7 @@ module_init(ata_init);
 module_exit(ata_exit);
 
 static unsigned long ratelimit_time;
-static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ata_ratelimit_lock);
 
 int ata_ratelimit(void)
 {
index 823385981a7a59f85ef69fb4c2799029182e791d..bf5a72aca8a4979957ae9a7ce8ff519d70490655 100644 (file)
@@ -93,6 +93,38 @@ static int ata_ering_map(struct ata_ering *ering,
        return rc;
 }
 
+static unsigned int ata_eh_dev_action(struct ata_device *dev)
+{
+       struct ata_eh_context *ehc = &dev->ap->eh_context;
+
+       return ehc->i.action | ehc->i.dev_action[dev->devno];
+}
+
+static void ata_eh_clear_action(struct ata_device *dev,
+                               struct ata_eh_info *ehi, unsigned int action)
+{
+       int i;
+
+       if (!dev) {
+               ehi->action &= ~action;
+               for (i = 0; i < ATA_MAX_DEVICES; i++)
+                       ehi->dev_action[i] &= ~action;
+       } else {
+               /* doesn't make sense for port-wide EH actions */
+               WARN_ON(!(action & ATA_EH_PERDEV_MASK));
+
+               /* break ehi->action into ehi->dev_action */
+               if (ehi->action & action) {
+                       for (i = 0; i < ATA_MAX_DEVICES; i++)
+                               ehi->dev_action[i] |= ehi->action & action;
+                       ehi->action &= ~action;
+               }
+
+               /* turn off the specified per-dev action */
+               ehi->dev_action[dev->devno] &= ~action;
+       }
+}
+
 /**
  *     ata_scsi_timed_out - SCSI layer time out callback
  *     @cmd: timed out SCSI command
@@ -702,32 +734,11 @@ static void ata_eh_detach_dev(struct ata_device *dev)
                ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
        }
 
-       spin_unlock_irqrestore(ap->lock, flags);
-}
-
-static void ata_eh_clear_action(struct ata_device *dev,
-                               struct ata_eh_info *ehi, unsigned int action)
-{
-       int i;
+       /* clear per-dev EH actions */
+       ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
+       ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
 
-       if (!dev) {
-               ehi->action &= ~action;
-               for (i = 0; i < ATA_MAX_DEVICES; i++)
-                       ehi->dev_action[i] &= ~action;
-       } else {
-               /* doesn't make sense for port-wide EH actions */
-               WARN_ON(!(action & ATA_EH_PERDEV_MASK));
-
-               /* break ehi->action into ehi->dev_action */
-               if (ehi->action & action) {
-                       for (i = 0; i < ATA_MAX_DEVICES; i++)
-                               ehi->dev_action[i] |= ehi->action & action;
-                       ehi->action &= ~action;
-               }
-
-               /* turn off the specified per-dev action */
-               ehi->dev_action[dev->devno] &= ~action;
-       }
+       spin_unlock_irqrestore(ap->lock, flags);
 }
 
 /**
@@ -1592,7 +1603,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
                unsigned int action;
 
                dev = &ap->device[i];
-               action = ehc->i.action | ehc->i.dev_action[dev->devno];
+               action = ata_eh_dev_action(dev);
 
                if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) {
                        if (ata_port_offline(ap)) {
index 93d18a74c401c37fe194422377736718c8bb02b1..2915bca691e8e941bd3813ab63b7de41532ef564 100644 (file)
@@ -222,9 +222,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
         && copy_to_user(arg + sizeof(args), argbuf, argsize))
                rc = -EFAULT;
 error:
-       if (argbuf)
-               kfree(argbuf);
-
+       kfree(argbuf);
        return rc;
 }
 
index bdd48889709678da69f8c4f7503c8c464ef3039b..c325679d9b545dc666496b941f91128d39a38546 100644 (file)
@@ -29,7 +29,7 @@
 #define __LIBATA_H__
 
 #define DRV_NAME       "libata"
-#define DRV_VERSION    "1.30"  /* must be exactly four chars */
+#define DRV_VERSION    "2.00"  /* must be exactly four chars */
 
 struct ata_scsi_args {
        struct ata_device       *dev;
@@ -50,6 +50,7 @@ extern void ata_port_flush_task(struct ata_port *ap);
 extern unsigned ata_exec_internal(struct ata_device *dev,
                                  struct ata_taskfile *tf, const u8 *cdb,
                                  int dma_dir, void *buf, unsigned int buflen);
+extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
 extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                           int post_reset, u16 *id);
 extern int ata_dev_configure(struct ata_device *dev, int print_info);
@@ -64,6 +65,7 @@ extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
 extern void ata_dev_select(struct ata_port *ap, unsigned int device,
                            unsigned int wait, unsigned int can_sleep);
 extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
+extern int ata_flush_cache(struct ata_device *dev);
 extern void ata_dev_init(struct ata_device *dev);
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
index d18e7e0932effc420c3fd0a21483dd1044bc4fdc..5cc42c6054eb66ebd8dbc67052b3e86ca4f2032a 100644 (file)
@@ -44,7 +44,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME                       "sata_nv"
-#define DRV_VERSION                    "0.9"
+#define DRV_VERSION                    "2.0"
 
 enum {
        NV_PORTS                        = 2,
index bc9f918a7f286e2e07690cc5e64ec3376fd58aa3..51d86d750e84f6892b05c98beaa9ac7f82e09fcb 100644 (file)
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_sil"
-#define DRV_VERSION    "1.0"
+#define DRV_VERSION    "2.0"
 
 enum {
        /*
         * host flags
         */
+       SIL_FLAG_NO_SATA_IRQ    = (1 << 28),
        SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
        SIL_FLAG_MOD15WRITE     = (1 << 30),
 
@@ -62,8 +63,9 @@ enum {
         * Controller IDs
         */
        sil_3112                = 0,
-       sil_3512                = 1,
-       sil_3114                = 2,
+       sil_3112_no_sata_irq    = 1,
+       sil_3512                = 2,
+       sil_3114                = 3,
 
        /*
         * Register offsets
@@ -123,8 +125,8 @@ static const struct pci_device_id sil_pci_tbl[] = {
        { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
        { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
        { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
-       { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
-       { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+       { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
        { }     /* terminate list */
 };
 
@@ -217,6 +219,16 @@ static const struct ata_port_info sil_port_info[] = {
                .udma_mask      = 0x3f,                 /* udma0-5 */
                .port_ops       = &sil_ops,
        },
+       /* sil_3112_no_sata_irq */
+       {
+               .sht            = &sil_sht,
+               .host_flags     = SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE |
+                                 SIL_FLAG_NO_SATA_IRQ,
+               .pio_mask       = 0x1f,                 /* pio0-4 */
+               .mwdma_mask     = 0x07,                 /* mwdma0-2 */
+               .udma_mask      = 0x3f,                 /* udma0-5 */
+               .port_ops       = &sil_ops,
+       },
        /* sil_3512 */
        {
                .sht            = &sil_sht,
@@ -437,6 +449,10 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance,
                if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
                        continue;
 
+               /* turn off SATA_IRQ if not supported */
+               if (ap->flags & SIL_FLAG_NO_SATA_IRQ)
+                       bmdma2 &= ~SIL_DMA_SATA_IRQ;
+
                if (bmdma2 == 0xffffffff ||
                    !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
                        continue;
@@ -474,8 +490,9 @@ static void sil_thaw(struct ata_port *ap)
        ata_chk_status(ap);
        ata_bmdma_irq_clear(ap);
 
-       /* turn on SATA IRQ */
-       writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
+       /* turn on SATA IRQ if supported */
+       if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
+               writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
 
        /* turn on IRQ */
        tmp = readl(mmio_base + SIL_SYSCFG);
index c8b477c672475debae2c8994fefd290a3a660053..b5f8fa955679063e6420bfe915d36aa75760a75c 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "sata_sil24"
-#define DRV_VERSION    "0.24"
+#define DRV_VERSION    "0.3"
 
 /*
  * Port request block (PRB) 32 bytes
index c94b870cf378af39df82966e20b59b04876fe395..7566c2cabaf725bcde3d2c7ac4fa09add5259e0e 100644 (file)
@@ -54,7 +54,7 @@
 #endif /* CONFIG_PPC_OF */
 
 #define DRV_NAME       "sata_svw"
-#define DRV_VERSION    "1.8"
+#define DRV_VERSION    "2.0"
 
 enum {
        /* Taskfile registers offsets */
index f668c997e9af0bccf3637fe60375c6ebbd7ee661..64f3c1aeed217d5f07250a69c8f8e8afacff8d77 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_uli"
-#define DRV_VERSION    "0.6"
+#define DRV_VERSION    "1.0"
 
 enum {
        uli_5289                = 0,
index 322890b400a6000a9d627fa44d69fcabdfe9f131..501ce1791782a7284f5af4614d1552468d29bb5b 100644 (file)
@@ -47,7 +47,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "sata_via"
-#define DRV_VERSION    "1.2"
+#define DRV_VERSION    "2.0"
 
 enum board_ids_enum {
        vt6420,
@@ -335,10 +335,10 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                if ((pci_resource_start(pdev, i) == 0) ||
                    (pci_resource_len(pdev, i) < bar_sizes[i])) {
                        dev_printk(KERN_ERR, &pdev->dev,
-                                  "invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n",
-                                  i,
-                                  pci_resource_start(pdev, i),
-                                  pci_resource_len(pdev, i));
+                               "invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n",
+                               i,
+                               (unsigned long long)pci_resource_start(pdev, i),
+                               (unsigned long long)pci_resource_len(pdev, i));
                        rc = -ENODEV;
                        goto err_out_regions;
                }
index 6d0c4f18e652ed42acec91830c8bde7fb875598c..616fd9634b4b0deb83a09e62dbde168c0da849ca 100644 (file)
@@ -47,7 +47,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_vsc"
-#define DRV_VERSION    "1.2"
+#define DRV_VERSION    "2.0"
 
 enum {
        /* Interrupt register offsets (from chip base address) */
@@ -443,16 +443,12 @@ err_out:
 }
 
 
-/*
- * Intel 31244 is supposed to be identical.
- * Compatibility is untested as of yet.
- */
 static const struct pci_device_id vsc_sata_pci_tbl[] = {
-       { PCI_VENDOR_ID_VITESSE, PCI_DEVICE_ID_VITESSE_VSC7174,
+       { PCI_VENDOR_ID_VITESSE, 0x7174,
          PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
-       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GD31244,
+       { PCI_VENDOR_ID_INTEL, 0x3200,
          PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
-       { }
+       { }     /* terminate list */
 };
 
 
index 7572665a885516d89ece6dcb5898154a14be2916..9fd0de4b7afdb961608af0d0c62b1e7c8d56cbf6 100644 (file)
@@ -479,7 +479,6 @@ static struct uart_driver serial21285_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "ttyFB",
        .dev_name               = "ttyFB",
-       .devfs_name             = "ttyFB",
        .major                  = SERIAL_21285_MAJOR,
        .minor                  = SERIAL_21285_MINOR,
        .nr                     = 1,
index b88a7c1158af15b4cb34be96e142dbfd4bdce666..bff94541991c099047ce91fa47f6563da27ff825 100644 (file)
@@ -131,17 +131,6 @@ static int m68328_console_baud    = CONSOLE_BAUD_RATE;
 static int m68328_console_cbaud   = DEFAULT_CBAUD;
 
 
-/*
- * 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[SERIAL_XMIT_SIZE]; /* This is cheating */
-
 static inline int serial_paranoia_check(struct m68k_serial *info,
                                        char *name, const char *routine)
 {
@@ -211,16 +200,16 @@ static void rs_stop(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->name, "rs_stop"))
                return;
        
-       save_flags(flags); cli();
+       local_irq_save(flags);
        uart->ustcnt &= ~USTCNT_TXEN;
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 static void rs_put_char(char ch)
 {
         int flags, loops = 0;
 
-        save_flags(flags); cli();
+        local_irq_save(flags);
 
        while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
                loops++;
@@ -229,7 +218,7 @@ static void rs_put_char(char ch)
 
        UTX_TXDATA = ch;
         udelay(5);
-        restore_flags(flags);
+        local_irq_restore(flags);
 }
 
 static void rs_start(struct tty_struct *tty)
@@ -241,7 +230,7 @@ static void rs_start(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->name, "rs_start"))
                return;
        
-       save_flags(flags); cli();
+       local_irq_save(flags);
        if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
 #ifdef USE_INTS
                uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
@@ -249,7 +238,7 @@ static void rs_start(struct tty_struct *tty)
                uart->ustcnt |= USTCNT_TXEN;
 #endif
        }
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 /* Drop into either the boot monitor or kadb upon receiving a break
@@ -327,14 +316,6 @@ static void receive_chars(struct m68k_serial *info, struct pt_regs *regs,
                if(!tty)
                        goto clear_and_exit;
                
-               /*
-                * Make sure that we do not overflow the buffer
-                */
-               if (tty_request_buffer_room(tty, 1) == 0) {
-                       tty_schedule_flip(tty);
-                       return;
-               }
-
                flag = TTY_NORMAL;
 
                if(rx & URX_PARITY_ERROR) {
@@ -473,7 +454,7 @@ static int startup(struct m68k_serial * info)
                        return -ENOMEM;
        }
 
-       save_flags(flags); cli();
+       local_irq_save(flags);
 
        /*
         * Clear the FIFO buffers and disable them
@@ -506,7 +487,7 @@ static int startup(struct m68k_serial * info)
        change_speed(info);
 
        info->flags |= S_INITIALIZED;
-       restore_flags(flags);
+       local_irq_restore(flags);
        return 0;
 }
 
@@ -523,7 +504,7 @@ static void shutdown(struct m68k_serial * info)
        if (!(info->flags & S_INITIALIZED))
                return;
 
-       save_flags(flags); cli(); /* Disable interrupts */
+       local_irq_save(flags);
        
        if (info->xmit_buf) {
                free_page((unsigned long) info->xmit_buf);
@@ -534,7 +515,7 @@ static void shutdown(struct m68k_serial * info)
                set_bit(TTY_IO_ERROR, &info->tty->flags);
        
        info->flags &= ~S_INITIALIZED;
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 struct {
@@ -655,24 +636,24 @@ static void rs_fair_output(void)
        if (info == 0) return;
        if (info->xmit_buf == 0) return;
 
-       save_flags(flags);  cli();
+       local_irq_save(flags);
        left = info->xmit_cnt;
        while (left != 0) {
                c = info->xmit_buf[info->xmit_tail];
                info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
                info->xmit_cnt--;
-               restore_flags(flags);
+               local_irq_restore(flags);
 
                rs_put_char(c);
 
-               save_flags(flags);  cli();
+               local_irq_save(flags);
                left = min(info->xmit_cnt, left-1);
        }
 
        /* Last character is being transmitted now (hopefully). */
        udelay(5);
 
-       restore_flags(flags);
+       local_irq_restore(flags);
        return;
 }
 
@@ -720,11 +701,11 @@ static void rs_flush_chars(struct tty_struct *tty)
 #endif
 
        /* Enable transmitter */
-       save_flags(flags); cli();
+       local_irq_save(flags);
 
        if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
                        !info->xmit_buf) {
-               restore_flags(flags);
+               local_irq_restore(flags);
                return;
        }
 
@@ -749,7 +730,7 @@ static void rs_flush_chars(struct tty_struct *tty)
        while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
        }
 #endif
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 extern void console_printn(const char * b, int count);
@@ -768,18 +749,22 @@ static int rs_write(struct tty_struct * tty,
        if (!tty || !info->xmit_buf)
                return 0;
 
-       save_flags(flags);
+       local_save_flags(flags);
        while (1) {
-               cli();          
+               local_irq_disable();            
                c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                                   SERIAL_XMIT_SIZE - info->xmit_head));
+               local_irq_restore(flags);
+
                if (c <= 0)
                        break;
 
                memcpy(info->xmit_buf + info->xmit_head, buf, c);
+
+               local_irq_disable();
                info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
                info->xmit_cnt += c;
-               restore_flags(flags);
+               local_irq_restore(flags);
                buf += c;
                count -= c;
                total += c;
@@ -787,7 +772,7 @@ static int rs_write(struct tty_struct * tty,
 
        if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
                /* Enable transmitter */
-               cli();          
+               local_irq_disable();            
 #ifndef USE_INTS
                while(info->xmit_cnt) {
 #endif
@@ -807,9 +792,9 @@ static int rs_write(struct tty_struct * tty,
 #ifndef USE_INTS
                }
 #endif
-               restore_flags(flags);
+               local_irq_restore(flags);
        }
-       restore_flags(flags);
+
        return total;
 }
 
@@ -838,12 +823,13 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
 static void rs_flush_buffer(struct tty_struct *tty)
 {
        struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       unsigned long flags;
                                
        if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
                return;
-       cli();
+       local_irq_save(flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       sti();
+       local_irq_restore(flags);
        tty_wakeup(tty);
 }
 
@@ -973,14 +959,15 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
        m68328_uart *uart = &uart_addr[info->line];
 #endif
        unsigned char status;
+       unsigned long flags;
 
-       cli();
+       local_irq_save(flags);
 #ifdef CONFIG_SERIAL_68328_RTS_CTS
        status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
 #else
        status = 0;
 #endif
-       sti();
+       local_irq_restore(flags);
        put_user(status,value);
        return 0;
 }
@@ -994,14 +981,13 @@ static void send_break(struct m68k_serial * info, unsigned int duration)
         unsigned long flags;
         if (!info->port)
                 return;
-        save_flags(flags);
-        cli();
+        local_irq_save(flags);
 #ifdef USE_INTS        
        uart->utx.w |= UTX_SEND_BREAK;
        msleep_interruptible(duration);
        uart->utx.w &= ~UTX_SEND_BREAK;
 #endif         
-        restore_flags(flags);
+        local_irq_restore(flags);
 }
 
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
@@ -1060,7 +1046,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                                               (struct serial_struct *) arg);
                case TIOCSERGETLSR: /* Get line status register */
                        if (access_ok(VERIFY_WRITE, (void *) arg,
-                                               sizeof(unsigned int));
+                                               sizeof(unsigned int)))
                                return get_lsr_info(info, (unsigned int *) arg);
                        return -EFAULT;
                case TIOCSERGSTRUCT:
@@ -1113,10 +1099,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
                return;
        
-       save_flags(flags); cli();
+       local_irq_save(flags);
        
        if (tty_hung_up_p(filp)) {
-               restore_flags(flags);
+               local_irq_restore(flags);
                return;
        }
        
@@ -1138,7 +1124,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                info->count = 0;
        }
        if (info->count) {
-               restore_flags(flags);
+               local_irq_restore(flags);
                return;
        }
        info->flags |= S_CLOSING;
@@ -1186,7 +1172,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        }
        info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
        wake_up_interruptible(&info->close_wait);
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 /*
@@ -1262,9 +1248,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        info->count--;
        info->blocked_open++;
        while (1) {
-               cli();
+               local_irq_disable();
                m68k_rtsdtr(info, 1);
-               sti();
+               local_irq_enable();
                current->state = TASK_INTERRUPTIBLE;
                if (tty_hung_up_p(filp) ||
                    !(info->flags & S_INITIALIZED)) {
@@ -1444,7 +1430,7 @@ rs68328_init(void)
                return -ENOMEM;
        }
 
-       save_flags(flags); cli();
+       local_irq_save(flags);
 
        for(i=0;i<NR_PORTS;i++) {
 
@@ -1489,7 +1475,7 @@ rs68328_init(void)
                    serial_pm[i]->data = info;
 #endif
        }
-       restore_flags(flags);
+       local_irq_restore(flags);
        return 0;
 }
 
index bbf78aaf9e01f074d15bf6db21042feb9dec5591..f361b356bd1d693f79a8777e9a568fdc9878267b 100644 (file)
@@ -2354,7 +2354,6 @@ int __init serial8250_start_console(struct uart_port *port, char *options)
 static struct uart_driver serial8250_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "serial",
-       .devfs_name             = "tts/",
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
        .minor                  = 64,
index 94886c000d2a2e8ff9581d83423bee68cfeaa409..864ef859be5676e3c6638517e31d87d1a4045229 100644 (file)
@@ -594,8 +594,8 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
        else
                offset += idx * board->uart_offset;
 
-       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) /
-               (8 << board->reg_shift);
+       maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
+               (board->reg_shift + 3);
 
        if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
                return 1;
index db5b25fafed42dfc36261dc6a4232e88d068f18a..df9500bdaded4ebe5903e57e56dc16a746e7d6b7 100644 (file)
@@ -863,7 +863,6 @@ static struct uart_driver at91_uart = {
        .owner                  = THIS_MODULE,
        .driver_name            = "at91_serial",
        .dev_name               = AT91_DEVICENAME,
-       .devfs_name             = AT91_DEVICENAME,
        .major                  = SERIAL_AT91_MAJOR,
        .minor                  = MINOR_START,
        .nr                     = AT91_NR_UART,
index 89700141f87e0d41b462ce6881a9f0a775d98549..b84137cdeb2be6c55d361280f01021bb7ba70ad7 100644 (file)
@@ -2573,12 +2573,6 @@ static void flush_to_flip_buffer(struct e100_serial *info)
 
        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));
@@ -4884,7 +4878,7 @@ rs_init(void)
        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->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        driver->termios = serial_termios;
        driver->termios_locked = serial_termios_locked;
 
index bf71bad5c34f7ff14f3d55ec66d7f6db397e50b8..466d06cc7d3762473b812ddf45a4d4146dbd0e28 100644 (file)
@@ -768,11 +768,7 @@ void __init dz_serial_console_init(void)
 static struct uart_driver dz_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "serial",
-#ifdef CONFIG_DEVFS
-       .dev_name               = "tts/%d",
-#else
        .dev_name               = "ttyS%d",
-#endif
        .major                  = TTY_MAJOR,
        .minor                  = 64,
        .nr                     = DZ_NB_PORT,
index d202eb4f3848f0cade4b4b2ed841f34f76703241..da85bafa09423fab636cc784d3dd1c98eb5de9e9 100644 (file)
@@ -888,7 +888,6 @@ 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),
index 651772474ac17d6687b4722f337b06765c2e7524..56b093ecd779eac6c122130d08724ac92baa9f9c 100644 (file)
@@ -1085,7 +1085,6 @@ static struct console ip22zilog_console = {
 static struct uart_driver ip22zilog_reg = {
        .owner          = THIS_MODULE,
        .driver_name    = "serial",
-       .devfs_name     = "tts/",
        .dev_name       = "ttyS",
        .major          = TTY_MAJOR,
        .minor          = 64,
index 7d823705193cfd55cebe2323b95d8edbf5d44c62..f8262e6ad8d3c3fc9728e621248c2d54f70bf2e5 100644 (file)
@@ -588,13 +588,6 @@ void jsm_input(struct jsm_channel *ch)
        len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt);
        ld = tty_ldisc_ref(tp);
 
-       /*
-        * If the DONT_FLIP flag is on, don't flush our buffer, and act
-        * like the ld doesn't have any space to put the data right now.
-        */
-       if (test_bit(TTY_DONT_FLIP, &tp->flags))
-               len = 0;
-
        /*
         * If we were unable to get a reference to the ld,
         * don't flush our buffer, and act like the ld doesn't
index 321a40f33b5042c93db4baac5ef6300c1f7f1f68..6a2a25d9b59638762f0c1830dbbd7d6056094fcd 100644 (file)
@@ -1131,7 +1131,6 @@ console_initcall(m32r_sio_console_init);
 static struct uart_driver m32r_sio_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "sio",
-       .devfs_name             = "tts/",
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
        .minor                  = 64,
index 8ad242934368e43f66b7fbe1cbff628a047e9bc1..29c0630e3e64a2edfdfd83e98a098f313854a613 100644 (file)
@@ -1713,7 +1713,6 @@ mcfrs_init(void)
        /* Initialize the tty_driver structure */
        mcfrs_serial_driver->owner = THIS_MODULE;
        mcfrs_serial_driver->name = "ttyS";
-       mcfrs_serial_driver->devfs_name = "ttys/";
        mcfrs_serial_driver->driver_name = "serial";
        mcfrs_serial_driver->major = TTY_MAJOR;
        mcfrs_serial_driver->minor_start = 64;
index 6459edc7f5c5e09d23bef78c590abfe677a5a813..1aa34844218cee9065bf7e3f8d4304af5b688fff 100644 (file)
@@ -693,7 +693,6 @@ static struct uart_driver mpc52xx_uart_driver = {
        .owner          = THIS_MODULE,
        .driver_name    = "mpc52xx_psc_uart",
        .dev_name       = "ttyPSC",
-       .devfs_name     = "ttyPSC",
        .major          = SERIAL_PSC_MAJOR,
        .minor          = SERIAL_PSC_MINOR,
        .nr             = MPC52xx_PSC_MAXNUM,
index 94681922ea0a6a2e874bef249520ce541a035ee4..1cd102f84bfad80bd789016880ddb4a9f2d0c94d 100644 (file)
@@ -315,7 +315,6 @@ struct mpsc_port_info *mpsc_device_remove(int index);
 #define MPSC_MAJOR             204
 #define MPSC_MINOR_START       44
 #define        MPSC_DRIVER_NAME        "MPSC"
-#define        MPSC_DEVFS_NAME         "ttymm/"
 #define        MPSC_DEV_NAME           "ttyMM"
 #define        MPSC_VERSION            "1.00"
 
@@ -1863,7 +1862,6 @@ static struct platform_driver mpsc_shared_driver = {
 static struct uart_driver mpsc_reg = {
        .owner       = THIS_MODULE,
        .driver_name = MPSC_DRIVER_NAME,
-       .devfs_name  = MPSC_DEVFS_NAME,
        .dev_name    = MPSC_DEV_NAME,
        .major       = MPSC_MAJOR,
        .minor       = MPSC_MINOR_START,
index 513ff8597707bf5c642f0dd1d02aad97356fdf7f..e3ba7e17a240b8cc080c11aacc7979d49454403f 100644 (file)
@@ -101,7 +101,6 @@ static DEFINE_MUTEX(pmz_irq_mutex);
 static struct uart_driver pmz_uart_reg = {
        .owner          =       THIS_MODULE,
        .driver_name    =       "ttyS",
-       .devfs_name     =       "tts/",
        .dev_name       =       "ttyS",
        .major          =       TTY_MAJOR,
 };
index ae3649568541d091a24e121f391d061f514285fd..0fa0ccc9ed272b9c7dc8f9b4d71a64cc800969ed 100644 (file)
@@ -780,7 +780,6 @@ static struct uart_pxa_port serial_pxa_ports[] = {
 static struct uart_driver serial_pxa_reg = {
        .owner          = THIS_MODULE,
        .driver_name    = "PXA serial",
-       .devfs_name     = "tts/",
        .dev_name       = "ttyS",
        .major          = TTY_MAJOR,
        .minor          = 64,
index 837b6da520b3aeb0f9bbd0897ead81f123233b55..4c62ab949ecc3e01aaf04da45ca23cb7d2443a21 100644 (file)
@@ -149,7 +149,6 @@ s3c24xx_serial_dbg(const char *fmt, ...)
 /* 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
 
@@ -952,7 +951,6 @@ static struct uart_driver s3c24xx_uart_drv = {
        .nr             = 3,
        .cons           = S3C24XX_SERIAL_CONSOLE,
        .driver_name    = S3C24XX_SERIAL_NAME,
-       .devfs_name     = S3C24XX_SERIAL_DEVFS,
        .major          = S3C24XX_SERIAL_MAJOR,
        .minor          = S3C24XX_SERIAL_MINOR,
 };
index c2d9068b491d8c0dacb549b365196174ef0ec63f..8bbd8567669cdf955888cc0bccd4542a9470faab 100644 (file)
@@ -816,7 +816,6 @@ static struct uart_driver sa1100_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "ttySA",
        .dev_name               = "ttySA",
-       .devfs_name             = "ttySA",
        .major                  = SERIAL_SA1100_MAJOR,
        .minor                  = MINOR_START,
        .nr                     = NR_PORTS,
index 17839e753e4cfb1fb550832d8613b0ec579c83ef..7dc1e67b6851b2e0ade005e73be8aea60a7df782 100644 (file)
@@ -2153,7 +2153,6 @@ int uart_register_driver(struct uart_driver *drv)
 
        normal->owner           = drv->owner;
        normal->driver_name     = drv->driver_name;
-       normal->devfs_name      = drv->devfs_name;
        normal->name            = drv->dev_name;
        normal->major           = drv->major;
        normal->minor_start     = drv->minor;
@@ -2161,7 +2160,7 @@ int uart_register_driver(struct uart_driver *drv)
        normal->subtype         = SERIAL_TYPE_NORMAL;
        normal->init_termios    = tty_std_termios;
        normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       normal->flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        normal->driver_state    = drv;
        tty_set_operations(normal, &uart_ops);
 
@@ -2312,7 +2311,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
        mutex_unlock(&state->mutex);
 
        /*
-        * Remove the devices from devfs
+        * Remove the devices from the tty layer
         */
        tty_unregister_device(drv->tty_driver, port->line);
 
index 3bdee64d1a997101f12f49f9f7c509c25694cbd8..a901a7e446f3ca91c696989fd35426a5151401e2 100644 (file)
@@ -69,12 +69,10 @@ static char *serial_name = "TX39/49 Serial driver";
 #if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
 /* "ttyS" is used for standard serial driver */
 #define TXX9_TTY_NAME "ttyTX"
-#define TXX9_TTY_DEVFS_NAME "tttx/"
 #define TXX9_TTY_MINOR_START   (64 + 64)       /* ttyTX0(128), ttyTX1(129) */
 #else
 /* acts like standard serial driver */
 #define TXX9_TTY_NAME "ttyS"
-#define TXX9_TTY_DEVFS_NAME "tts/"
 #define TXX9_TTY_MINOR_START   64
 #endif
 #define TXX9_TTY_MAJOR TTY_MAJOR
@@ -971,7 +969,6 @@ console_initcall(serial_txx9_console_init);
 static struct uart_driver serial_txx9_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "serial_txx9",
-       .devfs_name             = TXX9_TTY_DEVFS_NAME,
        .dev_name               = TXX9_TTY_NAME,
        .major                  = TXX9_TTY_MAJOR,
        .minor                  = TXX9_TTY_MINOR_START,
index 44f6bf79bbe12725fc0ba499501ba49625bcda60..d97f3ca6cc29996b6f4a5ed274a2b90f0af1f05c 100644 (file)
@@ -1699,9 +1699,6 @@ static char banner[] __initdata =
 static struct uart_driver sci_uart_driver = {
        .owner          = THIS_MODULE,
        .driver_name    = "sci",
-#ifdef CONFIG_DEVFS_FS
-       .devfs_name     = "ttsc/",
-#endif
        .dev_name       = "ttySC",
        .major          = SCI_MAJOR,
        .minor          = SCI_MINOR_START,
index ba22e256c6f77267c8a95cb50b583ed349f994d6..d36bc4003399ed27021299a92585adbd1e062d66 100644 (file)
@@ -353,7 +353,6 @@ static struct uart_ops sunhv_pops = {
 static struct uart_driver sunhv_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "serial",
-       .devfs_name             = "tts/",
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
 };
index e4c0fd2d6a9d54f1332d60304fd2c6dd23b42f0f..7da02d11c364d99506051608c27242c76435dbeb 100644 (file)
@@ -851,7 +851,6 @@ static struct uart_ops sunsab_pops = {
 static struct uart_driver sunsab_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "serial",
-       .devfs_name             = "tts/",
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
 };
index 0268b307c01e439e96c248cd554bb6f73a4ba462..6e28c25138cf3cfb2a75de9b1372f4e8eb6dd2da 100644 (file)
@@ -1265,7 +1265,6 @@ out:
 static struct uart_driver sunsu_reg = {
        .owner                  = THIS_MODULE,
        .driver_name            = "serial",
-       .devfs_name             = "tts/",
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
 };
index 76c9bac9271f9a9bc110157303ef589d8f66269f..9f42677287ad55836455b3820370a828471ff947 100644 (file)
@@ -1017,7 +1017,6 @@ static int zilog_irq = -1;
 static struct uart_driver sunzilog_reg = {
        .owner          =       THIS_MODULE,
        .driver_name    =       "ttyS",
-       .devfs_name     =       "tts/",
        .dev_name       =       "ttyS",
        .major          =       TTY_MAJOR,
 };
index df705fda42436f392308138a2634ddb4628998f6..a0da2aaf71c4436d60de6d7086b5b21b682527bd 100644 (file)
@@ -468,7 +468,6 @@ static struct uart_ops v850e_uart_ops = {
 static struct uart_driver v850e_uart_driver = {
        .owner                  = THIS_MODULE,
        .driver_name            = "v850e_uart",
-       .devfs_name             = "tts/",
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
        .minor                  = V850E_UART_MINOR_BASE,
index df5e8713fa312290efab20f4794d00d1391b258a..017571ffa19cec0bd744cea32743fd561a99c4c8 100644 (file)
@@ -911,7 +911,6 @@ static struct uart_driver siu_uart_driver = {
        .owner          = THIS_MODULE,
        .driver_name    = "SIU",
        .dev_name       = "ttyVR",
-       .devfs_name     = "ttvr/",
        .major          = SIU_MAJOR,
        .minor          = SIU_MINOR_BASE,
        .cons           = SERIAL_VR41XX_CONSOLE,
index 501316b198e51123bcaf30618f002c7de589afc0..ed946311d3a47e3120185e909eeb9524185cf4bc 100644 (file)
@@ -26,7 +26,7 @@ static DECLARE_RWSEM(ioc3_devices_rwsem);
 
 static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES];
 static struct ioc3_submodule *ioc3_ethernet;
-static rwlock_t ioc3_submodules_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(ioc3_submodules_lock);
 
 /* NIC probing code */
 
index 8256a97eb508c1b4db3ff98574894091cb51dece..8562821e6498be2324f8763f17d1292c70f105a7 100644 (file)
@@ -438,7 +438,7 @@ static struct pci_device_id ioc4_id_table[] = {
        {0}
 };
 
-static struct pci_driver __devinitdata ioc4_driver = {
+static struct pci_driver ioc4_driver = {
        .name = "IOC4",
        .id_table = ioc4_id_table,
        .probe = ioc4_probe,
index 1cea4a6799fe66c3e6fd94eaf56b3ed52b13e2cb..ed1cdf6ac8f34dbe5d61a6b172b49ccea1bfdddd 100644 (file)
@@ -210,6 +210,7 @@ spi_new_device(struct spi_master *master, struct spi_board_info *chip)
        proxy->master = master;
        proxy->chip_select = chip->chip_select;
        proxy->max_speed_hz = chip->max_speed_hz;
+       proxy->mode = chip->mode;
        proxy->irq = chip->irq;
        proxy->modalias = chip->modalias;
 
index 2dffa8e303b27ade495f47fa3ef8ca01690adb7e..7f27b356eaf723450d3598db9d62a60a5ab3a441 100644 (file)
@@ -1745,7 +1745,6 @@ int __init zs_init(void)
        /* Not all of this is exactly right for us. */
 
        serial_driver->owner = THIS_MODULE;
-       serial_driver->devfs_name = "tts/";
        serial_driver->name = "ttyS";
        serial_driver->major = TTY_MAJOR;
        serial_driver->minor_start = 64;
@@ -1754,7 +1753,7 @@ int __init zs_init(void)
        serial_driver->init_termios = tty_std_termios;
        serial_driver->init_termios.c_cflag =
                B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        tty_set_operations(serial_driver, &serial_ops);
 
        if (tty_register_driver(serial_driver))
index e166fffea86ba5b971df5d6fd7e4f2c95240e689..e41f49afd0f4792dfe8e3b0290b398590a90d886 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <linux/kmod.h>
 #include <linux/sem.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/mutex.h>
 
 #define PHONE_NUM_DEVICES      256
@@ -106,8 +105,6 @@ int phone_register_device(struct phone_device *p, int unit)
                if (phone_device[i] == NULL) {
                        phone_device[i] = p;
                        p->minor = i;
-                       devfs_mk_cdev(MKDEV(PHONE_MAJOR,i),
-                               S_IFCHR|S_IRUSR|S_IWUSR, "phone/%d", i);
                        mutex_unlock(&phone_lock);
                        return 0;
                }
@@ -125,7 +122,6 @@ void phone_unregister_device(struct phone_device *pfd)
        mutex_lock(&phone_lock);
        if (phone_device[pfd->minor] != pfd)
                panic("phone: bad unregister");
-       devfs_remove("phone/%d", pfd->minor);
        phone_device[pfd->minor] = NULL;
        mutex_unlock(&phone_lock);
 }
index d41dc67ba4ccb74220dde9405a4df44ad86c93ce..3670d77e912ca4a068a3dc46e93ae8696aeca242 100644 (file)
@@ -1145,12 +1145,11 @@ static int __init acm_init(void)
        acm_tty_driver->owner = THIS_MODULE,
        acm_tty_driver->driver_name = "acm",
        acm_tty_driver->name = "ttyACM",
-       acm_tty_driver->devfs_name = "usb/acm/",
        acm_tty_driver->major = ACM_TTY_MAJOR,
        acm_tty_driver->minor_start = 0,
        acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
        acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
-       acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+       acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        acm_tty_driver->init_termios = tty_std_termios;
        acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
        tty_set_operations(acm_tty_driver, &acm_ops);
index 269ce7f4ad6608f56ab79aeb1e7e3a0d97593bc3..735e9dbd39fdfaedec41a6ac59f91a07bb0f1381 100644 (file)
@@ -60,7 +60,7 @@
 #include <linux/usb_ch9.h>
 #include <linux/usb_gadget.h>
 
-#include <asm/arch/hardware/intel_udc.h>
+#include <asm/arch/udc.h>
 
 
 /*
index 9d6e1d295528f5e30a17d5d3360ef6092cd56f55..416acac879df5d3b96d43d99bfe984a3bb9081bd 100644 (file)
@@ -588,12 +588,11 @@ static int __init gs_module_init(void)
        gs_tty_driver->owner = THIS_MODULE;
        gs_tty_driver->driver_name = GS_SHORT_NAME;
        gs_tty_driver->name = "ttygs";
-       gs_tty_driver->devfs_name = "usb/ttygs/";
        gs_tty_driver->major = GS_MAJOR;
        gs_tty_driver->minor_start = GS_MINOR_START;
        gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
        gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
-       gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        gs_tty_driver->init_termios = tty_std_termios;
        gs_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
        tty_set_operations(gs_tty_driver, &gs_tty_ops);
index 6b4bc3f2bd864fd28b3b135118db929735ecf016..89bcda5a329897aee7d5694b879595355190d84e 100644 (file)
@@ -1684,9 +1684,13 @@ sl811h_probe(struct platform_device *dev)
                if (!addr || !data)
                        return -ENODEV;
                ioaddr = 1;
-
-               addr_reg = (void __iomem *) addr->start;
-               data_reg = (void __iomem *) data->start;
+               /*
+                * NOTE: 64-bit resource->start is getting truncated
+                * to avoid compiler warning, assuming that ->start
+                * is always 32-bit for this case
+                */
+               addr_reg = (void __iomem *) (unsigned long) addr->start;
+               data_reg = (void __iomem *) (unsigned long) data->start;
        } else {
                addr_reg = ioremap(addr->start, 1);
                if (addr_reg == NULL) {
index 9432c73022758435fd9dbfaf1c374aee31079bbf..d7f3f736a6928fc760d2159e1562132935584e40 100644 (file)
@@ -453,8 +453,7 @@ static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
                        tty = port->tty;
 
                        /*
-                        *      FIXME: must not do this in IRQ context,
-                        *      must honour TTY_DONT_FLIP
+                        *      FIXME: must not do this in IRQ context
                         */
                        tty->ldisc.receive_buf(
                                tty,
index a30135c7cfe6a4f59550e2fce18fd18e43d4fc15..f466f89eeb6d542353652fe0f9d1a77f631f9fe6 100644 (file)
@@ -1059,13 +1059,12 @@ static int __init usb_serial_init(void)
 
        usb_serial_tty_driver->owner = THIS_MODULE;
        usb_serial_tty_driver->driver_name = "usbserial";
-       usb_serial_tty_driver->devfs_name = "usb/tts/";
        usb_serial_tty_driver->name =   "ttyUSB";
        usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
        usb_serial_tty_driver->minor_start = 0;
        usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
        usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
-       usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        usb_serial_tty_driver->init_termios = tty_std_termios;
        usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
        tty_set_operations(usb_serial_tty_driver, &serial_ops);
index 7de66b855d4e4e292d13182c40fafe0a44ceddac..1755dddf189908550b0dae24bdf8d2d498b1cc46 100644 (file)
@@ -40,14 +40,14 @@ static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
 
        mutex_unlock(&info->bl_mutex);
 
-       if (pdata->negative)
-               rlevel = MAX_RADEON_LEVEL - rlevel;
-
        if (rlevel < 0)
                rlevel = 0;
        else if (rlevel > MAX_RADEON_LEVEL)
                rlevel = MAX_RADEON_LEVEL;
 
+       if (pdata->negative)
+               rlevel = MAX_RADEON_LEVEL - rlevel;
+
        return rlevel;
 }
 
index d63c3f485853e52eb9b351bd7991295c05df1ebe..9ef68cd83bb4d0cc527524c073779fae21579d20 100644 (file)
@@ -743,8 +743,7 @@ void __exit au1100fb_cleanup(void)
 {
        driver_unregister(&au1100fb_driver);
 
-       if (drv_info.opt_mode)
-               kfree(drv_info.opt_mode);
+       kfree(drv_info.opt_mode);
 }
 
 module_init(au1100fb_init);
index a71e984c93d47aa8c8678ce1abb98a29b0a39336..ffc72ae3ada80a01f98c959099b004e57bc5aed4 100644 (file)
@@ -27,7 +27,7 @@
 
 static int hp680bl_suspended;
 static int current_intensity = 0;
-static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(bl_lock);
 static struct backlight_device *hp680_backlight_device;
 
 static void hp680bl_send_intensity(struct backlight_device *bd)
index f32b590730f237943c1589f401bceb9fc5211c5c..01401cd63ac061279a382f9884cb86424f2d0cd7 100644 (file)
@@ -390,7 +390,7 @@ static const char *vgacon_startup(void)
                vga_video_port_val = VGA_CRT_DM;
                if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
                        static struct resource ega_console_resource =
-                           { "ega", 0x3B0, 0x3BF };
+                           { .name = "ega", .start = 0x3B0, .end = 0x3BF };
                        vga_video_type = VIDEO_TYPE_EGAM;
                        vga_vram_size = 0x8000;
                        display_desc = "EGA+";
@@ -398,9 +398,9 @@ static const char *vgacon_startup(void)
                                         &ega_console_resource);
                } else {
                        static struct resource mda1_console_resource =
-                           { "mda", 0x3B0, 0x3BB };
+                           { .name = "mda", .start = 0x3B0, .end = 0x3BB };
                        static struct resource mda2_console_resource =
-                           { "mda", 0x3BF, 0x3BF };
+                           { .name = "mda", .start = 0x3BF, .end = 0x3BF };
                        vga_video_type = VIDEO_TYPE_MDA;
                        vga_vram_size = 0x2000;
                        display_desc = "*MDA";
@@ -423,14 +423,14 @@ static const char *vgacon_startup(void)
 
                        if (!ORIG_VIDEO_ISVGA) {
                                static struct resource ega_console_resource
-                                   = { "ega", 0x3C0, 0x3DF };
+                                   = { .name = "ega", .start = 0x3C0, .end = 0x3DF };
                                vga_video_type = VIDEO_TYPE_EGAC;
                                display_desc = "EGA";
                                request_resource(&ioport_resource,
                                                 &ega_console_resource);
                        } else {
                                static struct resource vga_console_resource
-                                   = { "vga+", 0x3C0, 0x3DF };
+                                   = { .name = "vga+", .start = 0x3C0, .end = 0x3DF };
                                vga_video_type = VIDEO_TYPE_VGAC;
                                display_desc = "VGA+";
                                request_resource(&ioport_resource,
@@ -474,7 +474,7 @@ static const char *vgacon_startup(void)
                        }
                } else {
                        static struct resource cga_console_resource =
-                           { "cga", 0x3D4, 0x3D5 };
+                           { .name = "cga", .start = 0x3D4, .end = 0x3D5 };
                        vga_video_type = VIDEO_TYPE_CGA;
                        vga_vram_size = 0x2000;
                        display_desc = "*CGA";
index 31143afe7c95899303bac5571dcf833e7c26174e..a171daab0ad0b7467f97c5fde87fefb1ec1f8569 100644 (file)
@@ -32,7 +32,6 @@
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
-#include <linux/devfs_fs_kernel.h>
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/efi.h>
@@ -1331,8 +1330,6 @@ register_framebuffer(struct fb_info *fb_info)
        fb_add_videomode(&mode, &fb_info->modelist);
        registered_fb[i] = fb_info;
 
-       devfs_mk_cdev(MKDEV(FB_MAJOR, i),
-                       S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i);
        event.info = fb_info;
        blocking_notifier_call_chain(&fb_notifier_list,
                            FB_EVENT_FB_REGISTERED, &event);
@@ -1359,7 +1356,6 @@ unregister_framebuffer(struct fb_info *fb_info)
        i = fb_info->node;
        if (!registered_fb[i])
                return -EINVAL;
-       devfs_remove("fb/%d", i);
 
        if (fb_info->pixmap.addr &&
            (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
@@ -1432,7 +1428,6 @@ fbmem_init(void)
 {
        create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);
 
-       devfs_mk_dir("fb");
        if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
                printk("unable to get major %d for fb devs\n", FB_MAJOR);
 
index 2e6df1fcb2b926e875508bc8ff3181bb4d89a7bc..c0cc5e3ba7b5fe28d689071a52836897d8450627 100644 (file)
@@ -23,6 +23,8 @@
 #include <asm/io.h>
 #include <asm/mtrr.h>
 
+#include <setup_arch.h>
+
 #define INCLUDE_TIMING_TABLE_DATA
 #define DBE_REG_BASE par->regs
 #include <video/sgivw.h>
@@ -42,10 +44,6 @@ struct sgivw_par {
  *  The default can be overridden if the driver is compiled as a module
  */
 
-/* set by arch/i386/kernel/setup.c */
-extern unsigned long sgivwfb_mem_phys;
-extern unsigned long sgivwfb_mem_size;
-
 static int ypan = 0;
 static int ywrap = 0;
 
index 12e1baa4508d6569753284260d04878849cf8aa3..8d45ed6688376461f357ca69d6ec6c9abe3c671a 100644 (file)
@@ -932,6 +932,8 @@ v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
                                        r.rcall || r.err);
                        } while (!r.rcall && !r.err && err==-ERESTARTSYS &&
                                m->trans->status==Connected && !m->err);
+
+                       err = -ERESTARTSYS;
                }
                sigpending = 1;
        }
index f867b8d3e973a069d1d0bf21495114963e36a0a0..450b0c1b385e62f31db2d74ce6990fd67f8aeedc 100644 (file)
@@ -38,7 +38,7 @@
  */
 
 extern struct file_system_type v9fs_fs_type;
-extern struct address_space_operations v9fs_addr_operations;
+extern const struct address_space_operations v9fs_addr_operations;
 extern const struct file_operations v9fs_file_operations;
 extern const struct file_operations v9fs_dir_operations;
 extern struct dentry_operations v9fs_dentry_operations;
index efda46fb64d9e5a0bacaa14ead4f0414e04b07f6..d4f0aa3c87f2fc2717413169d5ec651cda144aa8 100644 (file)
@@ -103,6 +103,6 @@ UnmapAndUnlock:
        return retval;
 }
 
-struct address_space_operations v9fs_addr_operations = {
+const struct address_space_operations v9fs_addr_operations = {
       .readpage = v9fs_vfs_readpage,
 };
index 5c6bdf82146c3618caeae2f9ff5a1f2832e89fae..2f580a197b8dadf573ce7093742e4e647c950c82 100644 (file)
@@ -300,7 +300,7 @@ clunk_fid:
        fid = V9FS_NOFID;
 
 put_fid:
-       if (fid >= 0)
+       if (fid != V9FS_NOFID)
                v9fs_put_idpool(fid, &v9ses->fidpool);
 
        kfree(fcall);
index 6c5051802bd285bebefc266a282cf3539846850f..6dc8cfd6d80cf7e57a73e1be4828b945667894d4 100644 (file)
@@ -1116,7 +1116,7 @@ config JFFS2_SUMMARY
 
 config JFFS2_FS_XATTR
        bool "JFFS2 XATTR support (EXPERIMENTAL)"
-       depends on JFFS2_FS && EXPERIMENTAL && !JFFS2_FS_WRITEBUFFER
+       depends on JFFS2_FS && EXPERIMENTAL
        default n
        help
          Extended attributes are name:value pairs associated with inodes by
@@ -1722,7 +1722,7 @@ config CIFS_STATS
          mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
 
 config CIFS_STATS2
-       bool "CIFS extended statistics"
+       bool "Extended statistics"
        depends on CIFS_STATS
        help
          Enabling this option will allow more detailed statistics on SMB
@@ -1735,6 +1735,32 @@ config CIFS_STATS2
          Unless you are a developer or are doing network performance analysis
          or tuning, say N.
 
+config CIFS_WEAK_PW_HASH
+       bool "Support legacy servers which use weaker LANMAN security"
+       depends on CIFS
+       help
+         Modern CIFS servers including Samba and most Windows versions
+         (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
+         security mechanisms. These hash the password more securely
+         than the mechanisms used in the older LANMAN version of the
+          SMB protocol needed to establish sessions with old SMB servers.
+
+         Enabling this option allows the cifs module to mount to older
+         LANMAN based servers such as OS/2 and Windows 95, but such
+         mounts may be less secure than mounts using NTLM or more recent
+         security mechanisms if you are on a public network.  Unless you
+         have a need to access old SMB servers (and are on a private 
+         network) you probably want to say N.  Even if this support
+         is enabled in the kernel build, they will not be used
+         automatically. At runtime LANMAN mounts are disabled but
+         can be set to required (or optional) either in
+         /proc/fs/cifs (see fs/cifs/README for more detail) or via an
+         option on the mount command. This support is disabled by 
+         default in order to reduce the possibility of a downgrade
+         attack.
+         If unsure, say N.
+
 config CIFS_XATTR
         bool "CIFS extended attributes"
         depends on CIFS
@@ -1763,6 +1789,16 @@ config CIFS_POSIX
          (such as Samba 3.10 and later) which can negotiate
          CIFS POSIX ACL support.  If unsure, say N.
 
+config CIFS_DEBUG2
+       bool "Enable additional CIFS debugging routines"
+       help
+          Enabling this option adds a few more debugging routines
+          to the cifs code which slightly increases the size of
+          the cifs module and can cause additional logging of debug
+          messages in some error paths, slowing performance. This
+          option can be turned off unless you are debugging
+          cifs problems.  If unsure, say N.
+          
 config CIFS_EXPERIMENTAL
          bool "CIFS Experimental Features (EXPERIMENTAL)"
          depends on CIFS && EXPERIMENTAL
@@ -1778,7 +1814,7 @@ config CIFS_EXPERIMENTAL
            If unsure, say N.
 
 config CIFS_UPCALL
-         bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
+         bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
          depends on CIFS_EXPERIMENTAL
          select CONNECTOR
          help
index d0ea6bfccf29a6071144919b44e3b31f064ed879..89135428a539184580b2b0305ec46f6e7d5bfa86 100644 (file)
@@ -66,7 +66,6 @@ obj-$(CONFIG_MSDOS_FS)                += msdos/
 obj-$(CONFIG_VFAT_FS)          += vfat/
 obj-$(CONFIG_BFS_FS)           += bfs/
 obj-$(CONFIG_ISO9660_FS)       += isofs/
-obj-$(CONFIG_DEVFS_FS)         += devfs/
 obj-$(CONFIG_HFSPLUS_FS)       += hfsplus/ # Before hfs to find wrapped HFS+
 obj-$(CONFIG_HFS_FS)           += hfs/
 obj-$(CONFIG_VXFS_FS)          += freevxfs/
index a02802a30798a0eefe36f52e8302f0d1b8c70a38..534f3eecc985c7b5bfe9231bd4807db4091e388d 100644 (file)
@@ -72,7 +72,7 @@ static sector_t _adfs_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping, block, adfs_get_block);
 }
 
-static struct address_space_operations adfs_aops = {
+static const struct address_space_operations adfs_aops = {
        .readpage       = adfs_readpage,
        .writepage      = adfs_writepage,
        .sync_page      = block_sync_page,
index a43a876742b8e3b9759c7429e475bb62f5fb7e61..0ddd4cc0d1a0b598ca934b67ba6598b23bc725b7 100644 (file)
@@ -195,9 +195,9 @@ extern struct inode_operations   affs_symlink_inode_operations;
 extern const struct file_operations     affs_file_operations;
 extern const struct file_operations     affs_file_operations_ofs;
 extern const struct file_operations     affs_dir_operations;
-extern struct address_space_operations  affs_symlink_aops;
-extern struct address_space_operations  affs_aops;
-extern struct address_space_operations  affs_aops_ofs;
+extern const struct address_space_operations    affs_symlink_aops;
+extern const struct address_space_operations    affs_aops;
+extern const struct address_space_operations    affs_aops_ofs;
 
 extern struct dentry_operations         affs_dentry_operations;
 extern struct dentry_operations         affs_dentry_operations_intl;
index 7076262af39b39404c4ae2669392597934554602..3de8590e4f6a56a35d13e09be2e8a3012df2fb54 100644 (file)
@@ -406,7 +406,7 @@ static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,affs_get_block);
 }
-struct address_space_operations affs_aops = {
+const struct address_space_operations affs_aops = {
        .readpage = affs_readpage,
        .writepage = affs_writepage,
        .sync_page = block_sync_page,
@@ -759,7 +759,7 @@ out:
        goto done;
 }
 
-struct address_space_operations affs_aops_ofs = {
+const struct address_space_operations affs_aops_ofs = {
        .readpage = affs_readpage_ofs,
        //.writepage = affs_writepage_ofs,
        //.sync_page = affs_sync_page_ofs,
index 426f0f094f23b145372e3153731eb8112a172463..f802256a59330d96d537ac513f636b01a81eb79c 100644 (file)
@@ -66,7 +66,7 @@ fail:
        return err;
 }
 
-struct address_space_operations affs_symlink_aops = {
+const struct address_space_operations affs_symlink_aops = {
        .readpage       = affs_symlink_readpage,
 };
 
index 7bb716887e29b6029ea058d2c206502d1ad5605c..67d6634101fdcc81e75787c87d8084f5c13256c9 100644 (file)
@@ -35,7 +35,7 @@ struct inode_operations afs_file_inode_operations = {
        .getattr        = afs_inode_getattr,
 };
 
-struct address_space_operations afs_fs_aops = {
+const struct address_space_operations afs_fs_aops = {
        .readpage       = afs_file_readpage,
        .sync_page      = block_sync_page,
        .set_page_dirty = __set_page_dirty_nobuffers,
index 72febdf9a35af9379996eb51a9167e1c085aeb8b..e88b3b65ae494a2861c8447b0592e9a7abcc353c 100644 (file)
@@ -69,7 +69,7 @@ extern const struct file_operations afs_dir_file_operations;
 /*
  * file.c
  */
-extern struct address_space_operations afs_fs_aops;
+extern const struct address_space_operations afs_fs_aops;
 extern struct inode_operations afs_file_inode_operations;
 
 #ifdef AFS_CACHING_SUPPORT
index 08201fab26cde9e33778add4589356f931d2e1b4..a83e889a97cd7d8d79dd04fe29b5f0f43edbe890 100644 (file)
@@ -73,7 +73,7 @@ static struct inode_operations befs_dir_inode_operations = {
        .lookup         = befs_lookup,
 };
 
-static struct address_space_operations befs_aops = {
+static const struct address_space_operations befs_aops = {
        .readpage       = befs_readpage,
        .sync_page      = block_sync_page,
        .bmap           = befs_bmap,
index 9d791004b21ccbf02ccc7a6d01d01a64cddf0b70..31973bbbf0574d285c71e309cbdbc36de83d0784 100644 (file)
@@ -50,7 +50,7 @@ static inline struct bfs_inode_info *BFS_I(struct inode *inode)
 /* file.c */
 extern struct inode_operations bfs_file_inops;
 extern const struct file_operations bfs_file_operations;
-extern struct address_space_operations bfs_aops;
+extern const struct address_space_operations bfs_aops;
 
 /* dir.c */
 extern struct inode_operations bfs_dir_inops;
index d83cd74a2e4e681a061552e8c26e22070e41efa0..3d5aca28a0a0980922c83c0b197d1cf52cb27593 100644 (file)
@@ -153,7 +153,7 @@ static sector_t bfs_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping, block, bfs_get_block);
 }
 
-struct address_space_operations bfs_aops = {
+const struct address_space_operations bfs_aops = {
        .readpage       = bfs_readpage,
        .writepage      = bfs_writepage,
        .sync_page      = block_sync_page,
index 028d9fb9c2d536dafad7563e36874c0e8c934d91..909cb0595b4e5279a54176cf52e2a2287a4c0bef 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/slab.h>
 #include <linux/kmod.h>
 #include <linux/major.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
 #include <linux/highmem.h>
 #include <linux/blkdev.h>
@@ -1095,7 +1094,7 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        return blkdev_ioctl(file->f_mapping->host, file, cmd, arg);
 }
 
-struct address_space_operations def_blk_aops = {
+const struct address_space_operations def_blk_aops = {
        .readpage       = blkdev_readpage,
        .writepage      = blkdev_writepage,
        .sync_page      = block_sync_page,
index 373bb6292bdc137a606296c7864093470d41b00f..e9994722f4a30959019e1df6e0516f8da23b9402 100644 (file)
@@ -564,7 +564,7 @@ still_busy:
  * Completion handler for block_write_full_page() - pages which are unlocked
  * during I/O, and which have PageWriteback cleared upon I/O completion.
  */
-void end_buffer_async_write(struct buffer_head *bh, int uptodate)
+static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
 {
        char b[BDEVNAME_SIZE];
        unsigned long flags;
@@ -2598,7 +2598,7 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from)
        unsigned offset = from & (PAGE_CACHE_SIZE-1);
        unsigned to;
        struct page *page;
-       struct address_space_operations *a_ops = mapping->a_ops;
+       const struct address_space_operations *a_ops = mapping->a_ops;
        char *kaddr;
        int ret = 0;
 
@@ -3166,7 +3166,6 @@ EXPORT_SYMBOL(block_sync_page);
 EXPORT_SYMBOL(block_truncate_page);
 EXPORT_SYMBOL(block_write_full_page);
 EXPORT_SYMBOL(cont_prepare_write);
-EXPORT_SYMBOL(end_buffer_async_write);
 EXPORT_SYMBOL(end_buffer_read_sync);
 EXPORT_SYMBOL(end_buffer_write_sync);
 EXPORT_SYMBOL(file_fsync);
index f3418f7a6e9d9da9bf894840cd23eba9be77d5b7..97986635b641393dd1b39cfc43eb4acdc1dbfc4e 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/seq_file.h>
 
 #include <linux/kobject.h>
index 7271bb0257f64f149d1fd3f9857416c1513787ae..a61d17ed1827e3552a6808a8f705fdd2281d7fe4 100644 (file)
@@ -1,9 +1,24 @@
+Version 1.44
+------------
+Rewritten sessionsetup support, including support for legacy SMB
+session setup needed for OS/2 and older servers such as Windows 95 and 98.
+Fix oops on ls to OS/2 servers.  Add support for level 1 FindFirst
+so we can do search (ls etc.) to OS/2.  Do not send NTCreateX
+or recent levels of FindFirst unless server says it supports NT SMBs
+(instead use legacy equivalents from LANMAN dialect). Fix to allow
+NTLMv2 authentication support (now can use stronger password hashing
+on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004).
+Allow override of global cifs security flags on mount via "sec=" option(s).
+
 Version 1.43
 ------------
 POSIX locking to servers which support CIFS POSIX Extensions
 (disabled by default controlled by proc/fs/cifs/Experimental).
 Handle conversion of long share names (especially Asian languages)
-to Unicode during mount. 
+to Unicode during mount. Fix memory leak in sess struct on reconnect.
+Fix rare oops after acpi suspend.  Fix O_TRUNC opens to overwrite on
+cifs open which helps rare case when setpathinfo fails or server does
+not support it. 
 
 Version 1.42
 ------------
index 58c77254a23b3dec24a11475a858aa2f96c1a6d2..a26f26ed5a17e78bb5caf31732be07d21e172a5f 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 readdir.o ioctl.o ntlmssp.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 ioctl.o sess.o
index 0355003f4f0a3b69eb021606d96f9e5261480c40..7986d0d97ace4f97b3b3d10b0800d03fcaabb631 100644 (file)
@@ -443,7 +443,10 @@ A partial list of the supported mount options follows:
                SFU does).  In the future the bottom 9 bits of the mode
                mode also will be emulated using queries of the security
                descriptor (ACL).
-sec            Security mode.  Allowed values are:
+ sign           Must use packet signing (helps avoid unwanted data modification
+               by intermediate systems in the route).  Note that signing
+               does not work with lanman or plaintext authentication.
+ sec            Security mode.  Allowed values are:
                        none    attempt to connection as a null user (no name)
                        krb5    Use Kerberos version 5 authentication
                        krb5i   Use Kerberos authentication and packet signing
@@ -453,6 +456,8 @@ sec         Security mode.  Allowed values are:
                                server requires signing also can be the default) 
                        ntlmv2  Use NTLMv2 password hashing      
                        ntlmv2i Use NTLMv2 password hashing with packet signing
+                       lanman  (if configured in kernel config) use older
+                               lanman hash
 
 The mount.cifs mount helper also accepts a few mount options before -o
 including:
@@ -485,14 +490,34 @@ PacketSigningEnabled      If set to one, cifs packet signing is enabled
                        it.  If set to two, cifs packet signing is
                        required even if the server considers packet
                        signing optional. (default 1)
+SecurityFlags          Flags which control security negotiation and
+                       also packet signing. Authentication (may/must)
+                       flags (e.g. for NTLM and/or NTLMv2) may be combined with
+                       the signing flags.  Specifying two different password
+                       hashing mechanisms (as "must use") on the other hand 
+                       does not make much sense. Default flags are 
+                               0x07007 
+                       (NTLM, NTLMv2 and packet signing allowed).  Maximum 
+                       allowable flags if you want to allow mounts to servers
+                       using weaker password hashes is 0x37037 (lanman,
+                       plaintext, ntlm, ntlmv2, signing allowed):
+                       may use packet signing                          0x00001
+                       must use packet signing                         0x01001
+                       may use NTLM (most common password hash)        0x00002
+                       must use NTLM                                   0x02002
+                       may use NTLMv2                                  0x00004
+                       must use NTLMv2                                 0x04004
+                       may use Kerberos security (not implemented yet) 0x00008
+                       must use Kerberos (not implemented yet)         0x08008
+                       may use lanman (weak) password hash             0x00010
+                       must use lanman password hash                   0x10010
+                       may use plaintext passwords                     0x00020
+                       must use plaintext passwords                    0x20020
+                       (reserved for future packet encryption)         0x00040
+
 cifsFYI                        If set to one, additional debug information is
                        logged to the system error log. (default 0)
-ExtendedSecurity       If set to one, SPNEGO session establishment
-                       is allowed which enables more advanced 
-                       secure CIFS session establishment (default 0)
-NTLMV2Enabled          If set to one, more secure password hashes
-                       are used when the server supports them and
-                       when kerberos is not negotiated (default 0)
 traceSMB               If set to one, debug information is logged to the
                        system error log with the start of smb requests
                        and responses (default 0)
index 086ae8f4a207a22f0d1bfe2863439ed20bd88f89..031cdf2932568ae5dea33d4813d5b8bac314e1c5 100644 (file)
@@ -467,7 +467,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
        asn1_open(&ctx, security_blob, length);
 
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-               cFYI(1, ("Error decoding negTokenInit header "));
+               cFYI(1, ("Error decoding negTokenInit header"));
                return 0;
        } else if ((cls != ASN1_APL) || (con != ASN1_CON)
                   || (tag != ASN1_EOC)) {
@@ -495,7 +495,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                }
 
                if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding negTokenInit "));
+                       cFYI(1, ("Error decoding negTokenInit"));
                        return 0;
                } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
                           || (tag != ASN1_EOC)) {
@@ -505,7 +505,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                }
 
                if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding negTokenInit "));
+                       cFYI(1, ("Error decoding negTokenInit"));
                        return 0;
                } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
                           || (tag != ASN1_SEQ)) {
@@ -515,7 +515,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                }
 
                if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding 2nd part of negTokenInit "));
+                       cFYI(1, ("Error decoding 2nd part of negTokenInit"));
                        return 0;
                } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
                           || (tag != ASN1_EOC)) {
@@ -527,7 +527,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
 
                if (asn1_header_decode
                    (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding 2nd part of negTokenInit "));
+                       cFYI(1, ("Error decoding 2nd part of negTokenInit"));
                        return 0;
                } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
                           || (tag != ASN1_SEQ)) {
index f4124a32bef8974edd3f02111f8e382a63f02199..96abeb7389784d4e3f5fa6eb4ee72ea8d66b947a 100644 (file)
@@ -39,7 +39,7 @@ cifs_dump_mem(char *label, void *data, int length)
        char *charptr = data;
        char buf[10], line[80];
 
-       printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", 
+       printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n", 
                label, length, data);
        for (i = 0; i < length; i += 16) {
                line[0] = 0;
@@ -57,6 +57,57 @@ cifs_dump_mem(char *label, void *data, int length)
        }
 }
 
+#ifdef CONFIG_CIFS_DEBUG2
+void cifs_dump_detail(struct smb_hdr * smb)
+{
+       cERROR(1,("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
+                 smb->Command, smb->Status.CifsError,
+                 smb->Flags, smb->Flags2, smb->Mid, smb->Pid));
+       cERROR(1,("smb buf %p len %d", smb, smbCalcSize_LE(smb)));
+}
+
+
+void cifs_dump_mids(struct TCP_Server_Info * server)
+{
+       struct list_head *tmp;
+       struct mid_q_entry * mid_entry;
+
+       if(server == NULL)
+               return;
+
+       cERROR(1,("Dump pending requests:"));
+       spin_lock(&GlobalMid_Lock);
+       list_for_each(tmp, &server->pending_mid_q) {
+               mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+               if(mid_entry) {
+                       cERROR(1,("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
+                               mid_entry->midState,
+                               (int)mid_entry->command,
+                               mid_entry->pid,
+                               mid_entry->tsk,
+                               mid_entry->mid));
+#ifdef CONFIG_CIFS_STATS2
+                       cERROR(1,("IsLarge: %d buf: %p time rcv: %ld now: %ld",
+                               mid_entry->largeBuf,
+                               mid_entry->resp_buf,
+                               mid_entry->when_received,
+                               jiffies));
+#endif /* STATS2 */
+                       cERROR(1,("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
+                                 mid_entry->multiEnd));
+                       if(mid_entry->resp_buf) {
+                               cifs_dump_detail(mid_entry->resp_buf);
+                               cifs_dump_mem("existing buf: ",
+                                       mid_entry->resp_buf,
+                                       62 /* fixme */);
+                       }
+                       
+               }
+       }
+       spin_unlock(&GlobalMid_Lock);
+}
+#endif /* CONFIG_CIFS_DEBUG2 */
+
 #ifdef CONFIG_PROC_FS
 static int
 cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
@@ -73,7 +124,6 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 
        *beginBuffer = buf + offset;
 
-       
        length =
            sprintf(buf,
                    "Display Internal CIFS Data Structures for Debugging\n"
@@ -395,12 +445,12 @@ static read_proc_t traceSMB_read;
 static write_proc_t traceSMB_write;
 static read_proc_t multiuser_mount_read;
 static write_proc_t multiuser_mount_write;
-static read_proc_t extended_security_read;
-static write_proc_t extended_security_write;
-static read_proc_t ntlmv2_enabled_read;
+static read_proc_t security_flags_read;
+static write_proc_t security_flags_write;
+/* static read_proc_t ntlmv2_enabled_read;
 static write_proc_t ntlmv2_enabled_write;
 static read_proc_t packet_signing_enabled_read;
-static write_proc_t packet_signing_enabled_write;
+static write_proc_t packet_signing_enabled_write;*/
 static read_proc_t experimEnabled_read;
 static write_proc_t experimEnabled_write;
 static read_proc_t linuxExtensionsEnabled_read;
@@ -458,10 +508,10 @@ cifs_proc_init(void)
                pde->write_proc = multiuser_mount_write;
 
        pde =
-           create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs,
-                               extended_security_read, NULL);
+           create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs,
+                               security_flags_read, NULL);
        if (pde)
-               pde->write_proc = extended_security_write;
+               pde->write_proc = security_flags_write;
 
        pde =
        create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs,
@@ -469,7 +519,7 @@ cifs_proc_init(void)
        if (pde)
                pde->write_proc = lookupFlag_write;
 
-       pde =
+/*     pde =
            create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
                                ntlmv2_enabled_read, NULL);
        if (pde)
@@ -479,7 +529,7 @@ cifs_proc_init(void)
            create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
                                packet_signing_enabled_read, NULL);
        if (pde)
-               pde->write_proc = packet_signing_enabled_write;
+               pde->write_proc = packet_signing_enabled_write;*/
 }
 
 void
@@ -496,9 +546,9 @@ cifs_proc_clean(void)
 #endif
        remove_proc_entry("MultiuserMount", proc_fs_cifs);
        remove_proc_entry("OplockEnabled", proc_fs_cifs);
-       remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
-       remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
-       remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
+/*     remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
+       remove_proc_entry("SecurityFlags",proc_fs_cifs);
+/*     remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */
        remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
        remove_proc_entry("Experimental",proc_fs_cifs);
        remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
@@ -782,12 +832,12 @@ multiuser_mount_write(struct file *file, const char __user *buffer,
 }
 
 static int
-extended_security_read(char *page, char **start, off_t off,
+security_flags_read(char *page, char **start, off_t off,
                       int count, int *eof, void *data)
 {
        int len;
 
-       len = sprintf(page, "%d\n", extended_security);
+       len = sprintf(page, "0x%x\n", extended_security);
 
        len -= off;
        *start = page + off;
@@ -803,24 +853,52 @@ extended_security_read(char *page, char **start, off_t off,
        return len;
 }
 static int
-extended_security_write(struct file *file, const char __user *buffer,
+security_flags_write(struct file *file, const char __user *buffer,
                        unsigned long count, void *data)
 {
+       unsigned int flags;
+       char flags_string[12];
        char c;
-       int rc;
 
-       rc = get_user(c, buffer);
-       if (rc)
-               return rc;
-       if (c == '0' || c == 'n' || c == 'N')
-               extended_security = 0;
-       else if (c == '1' || c == 'y' || c == 'Y')
-               extended_security = 1;
+       if((count < 1) || (count > 11))
+               return -EINVAL;
+
+       memset(flags_string, 0, 12);
+
+       if(copy_from_user(flags_string, buffer, count))
+               return -EFAULT;
+
+       if(count < 3) {
+               /* single char or single char followed by null */
+               c = flags_string[0];
+               if (c == '0' || c == 'n' || c == 'N')
+                       extended_security = CIFSSEC_DEF; /* default */
+               else if (c == '1' || c == 'y' || c == 'Y')
+                       extended_security = CIFSSEC_MAX;
+               return count;
+       }
+       /* else we have a number */
+
+       flags = simple_strtoul(flags_string, NULL, 0);
+
+       cFYI(1,("sec flags 0x%x", flags));
+
+       if(flags <= 0)  {
+               cERROR(1,("invalid security flags %s",flags_string));
+               return -EINVAL;
+       }
 
+       if(flags & ~CIFSSEC_MASK) {
+               cERROR(1,("attempt to set unsupported security flags 0x%x",
+                       flags & ~CIFSSEC_MASK));
+               return -EINVAL;
+       }
+       /* flags look ok - update the global security flags for cifs module */
+       extended_security = flags;
        return count;
 }
 
-static int
+/* static int
 ntlmv2_enabled_read(char *page, char **start, off_t off,
                       int count, int *eof, void *data)
 {
@@ -855,6 +933,8 @@ ntlmv2_enabled_write(struct file *file, const char __user *buffer,
                ntlmv2_support = 0;
        else if (c == '1' || c == 'y' || c == 'Y')
                ntlmv2_support = 1;
+       else if (c == '2')
+               ntlmv2_support = 2;
 
        return count;
 }
@@ -898,7 +978,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer,
                sign_CIFS_PDUs = 2;
 
        return count;
-}
+} */
 
 
 #endif
index 4304d9dcfb6c6501853b533f7f3d320fcbcd95bf..c26cd0d2c6d525d64455dfba60e9fdd5b9a4243a 100644 (file)
 #define _H_CIFS_DEBUG
 
 void cifs_dump_mem(char *label, void *data, int length);
+#ifdef CONFIG_CIFS_DEBUG2
+void cifs_dump_detail(struct smb_hdr *);
+void cifs_dump_mids(struct TCP_Server_Info *);
+#endif
 extern int traceSMB;           /* flag which enables the function below */
 void dump_smb(struct smb_hdr *, int);
 #define CIFS_INFO      0x01
index d2b128255944269506f5395506528a4009d7d6dd..d2a8b2941fc26a2d752ccf8954f9fb31cfef026f 100644 (file)
@@ -22,6 +22,7 @@
 #include "cifs_unicode.h"
 #include "cifs_uniupr.h"
 #include "cifspdu.h"
+#include "cifsglob.h"
 #include "cifs_debug.h"
 
 /*
index e7d63737e65110c1be3fddb6f7974ab7a1f16c44..a89efaf78a266ef2d7a4c01d8f5876c5969504dc 100644 (file)
@@ -26,6 +26,8 @@
 #include "md5.h"
 #include "cifs_unicode.h"
 #include "cifsproto.h"
+#include <linux/ctype.h>
+#include <linux/random.h>
 
 /* Calculate and return the CIFS signature based on the mac key and the smb pdu */
 /* the 16 byte signature must be allocated by the caller  */
@@ -35,6 +37,8 @@
 
 extern void mdfour(unsigned char *out, unsigned char *in, int n);
 extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
+extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
+                       unsigned char *p24);
        
 static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, 
                                    const char * key, char * signature)
@@ -45,7 +49,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu,
                return -EINVAL;
 
        MD5Init(&context);
-       MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+       MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
        MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
        MD5Final(signature,&context);
        return 0;
@@ -90,7 +94,7 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
                return -EINVAL;
 
        MD5Init(&context);
-       MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+       MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
        for(i=0;i<n_vec;i++) {
                if(iov[i].iov_base == NULL) {
                        cERROR(1,("null iovec entry"));
@@ -204,11 +208,12 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
 
        E_md4hash(password, temp_key);
        mdfour(key,temp_key,16);
-       memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE);
+       memcpy(key+16,rn, CIFS_SESS_KEY_SIZE);
        return 0;
 }
 
-int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info)
+int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, 
+                               const struct nls_table * nls_info)
 {
        char temp_hash[16];
        struct HMACMD5Context ctx;
@@ -225,6 +230,8 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
        user_name_len = strlen(ses->userName);
        if(user_name_len > MAX_USERNAME_SIZE)
                return -EINVAL;
+       if(ses->domainName == NULL)
+               return -EINVAL; /* BB should we use CIFS_LINUX_DOM */
        dom_name_len = strlen(ses->domainName);
        if(dom_name_len > MAX_USERNAME_SIZE)
                return -EINVAL;
@@ -259,16 +266,131 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
        kfree(unicode_buf);
        return 0;
 }
-void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response)
+
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
+{
+       int i;
+       char password_with_pad[CIFS_ENCPWD_SIZE];
+
+       if(ses->server == NULL)
+               return;
+
+       memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+       strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
+
+       if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
+               if(extended_security & CIFSSEC_MAY_PLNTXT) {
+                       memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); 
+                       return;
+               }
+
+       /* calculate old style session key */
+       /* calling toupper is less broken than repeatedly
+       calling nls_toupper would be since that will never
+       work for UTF8, but neither handles multibyte code pages
+       but the only alternative would be converting to UCS-16 (Unicode)
+       (using a routine something like UniStrupr) then
+       uppercasing and then converting back from Unicode - which
+       would only worth doing it if we knew it were utf8. Basically
+       utf8 and other multibyte codepages each need their own strupper
+       function since a byte at a time will ont work. */
+
+       for(i = 0; i < CIFS_ENCPWD_SIZE; i++) {
+               password_with_pad[i] = toupper(password_with_pad[i]);
+       }
+
+       SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key);
+       /* clear password before we return/free memory */
+       memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+}
+#endif /* CIFS_WEAK_PW_HASH */
+
+static int calc_ntlmv2_hash(struct cifsSesInfo *ses, 
+                           const struct nls_table * nls_cp)
+{
+       int rc = 0;
+       int len;
+       char nt_hash[16];
+       struct HMACMD5Context * pctxt;
+       wchar_t * user;
+       wchar_t * domain;
+
+       pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);
+
+       if(pctxt == NULL)
+               return -ENOMEM;
+
+       /* calculate md4 hash of password */
+       E_md4hash(ses->password, nt_hash);
+
+       /* convert Domainname to unicode and uppercase */
+       hmac_md5_init_limK_to_64(nt_hash, 16, pctxt);
+
+       /* convert ses->userName to unicode and uppercase */
+       len = strlen(ses->userName);
+       user = kmalloc(2 + (len * 2), GFP_KERNEL);
+       if(user == NULL)
+               goto calc_exit_2;
+       len = cifs_strtoUCS(user, ses->userName, len, nls_cp);
+       UniStrupr(user);
+       hmac_md5_update((char *)user, 2*len, pctxt);
+
+       /* convert ses->domainName to unicode and uppercase */
+       if(ses->domainName) {
+               len = strlen(ses->domainName);
+
+               domain = kmalloc(2 + (len * 2), GFP_KERNEL);
+               if(domain == NULL)
+                       goto calc_exit_1;
+               len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp);
+               UniStrupr(domain);
+
+               hmac_md5_update((char *)domain, 2*len, pctxt);
+       
+               kfree(domain);
+       }
+calc_exit_1:
+       kfree(user);
+calc_exit_2:
+       /* BB FIXME what about bytes 24 through 40 of the signing key? 
+          compare with the NTLM example */
+       hmac_md5_final(ses->server->mac_signing_key, pctxt);
+
+       return rc;
+}
+
+void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, 
+                     const struct nls_table * nls_cp)
+{
+       int rc;
+       struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf;
+
+       buf->blob_signature = cpu_to_le32(0x00000101);
+       buf->reserved = 0;
+       buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+       get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
+       buf->reserved2 = 0;
+       buf->names[0].type = 0;
+       buf->names[0].length = 0;
+
+       /* calculate buf->ntlmv2_hash */
+       rc = calc_ntlmv2_hash(ses, nls_cp);
+       if(rc)
+               cERROR(1,("could not get v2 hash rc %d",rc));
+       CalcNTLMv2_response(ses, resp_buf);
+}
+
+void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response)
 {
        struct HMACMD5Context context;
+       /* rest of v2 struct already generated */
        memcpy(v2_session_response + 8, ses->server->cryptKey,8);
-       /* gen_blob(v2_session_response + 16); */
        hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
 
-       hmac_md5_update(ses->server->cryptKey,8,&context);
-/*     hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
+       hmac_md5_update(v2_session_response+8, 
+                       sizeof(struct ntlmv2_resp) - 8, &context);
 
        hmac_md5_final(v2_session_response,&context);
-       cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); /* BB removeme BB */
+/*     cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
 }
index 8b4de6eaabd0ee11bf329e02fa1060cd32a44d0c..c28ede599946842568356378cec5ed3eaff3f139 100644 (file)
@@ -56,8 +56,8 @@ unsigned int experimEnabled = 0;
 unsigned int linuxExtEnabled = 1;
 unsigned int lookupCacheEnabled = 1;
 unsigned int multiuser_mount = 0;
-unsigned int extended_security = 0;
-unsigned int ntlmv2_support = 0;
+unsigned int extended_security = CIFSSEC_DEF;
+/* unsigned int ntlmv2_support = 0; */
 unsigned int sign_CIFS_PDUs = 1;
 extern struct task_struct * oplockThread; /* remove sparse warning */
 struct task_struct * oplockThread = NULL;
@@ -908,7 +908,7 @@ static int cifs_dnotify_thread(void * dummyarg)
        struct cifsSesInfo *ses;
 
        do {
-               if(try_to_freeze())
+               if (try_to_freeze())
                        continue;
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(15*HZ);
index d56c0577c7103f95f1c8cd8068f1318cb45ab0cf..8f75c6f24701ff4e5a63f99cccb3b316830204bc 100644 (file)
@@ -32,7 +32,8 @@
 #define TRUE 1
 #endif
 
-extern struct address_space_operations cifs_addr_ops;
+extern const struct address_space_operations cifs_addr_ops;
+extern const struct address_space_operations cifs_addr_ops_smallbuf;
 
 /* Functions related to super block operations */
 extern struct super_operations cifs_super_ops;
@@ -99,5 +100,5 @@ extern ssize_t       cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
                       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.43"
+#define CIFS_VERSION   "1.44"
 #endif                         /* _CIFSFS_H */
index 006eb33bff5ff7e6a576b5804e95ec22eb50bb52..6d7cf5f3bc0bdb3549b7e038fdd099ada89bee3c 100644 (file)
@@ -88,7 +88,8 @@ enum statusEnum {
 };
 
 enum securityEnum {
-       NTLM = 0,               /* Legacy NTLM012 auth with NTLM hash */
+       LANMAN = 0,             /* Legacy LANMAN auth */
+       NTLM,                   /* Legacy NTLM012 auth with NTLM hash */
        NTLMv2,                 /* Legacy NTLM auth with NTLMv2 hash */
        RawNTLMSSP,             /* NTLMSSP without SPNEGO */
        NTLMSSP,                /* NTLMSSP via SPNEGO */
@@ -157,7 +158,7 @@ struct TCP_Server_Info {
        /* 16th byte of RFC1001 workstation name is always null */
        char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
        __u32 sequence_number; /* needed for CIFS PDU signature */
-       char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; 
+       char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; 
 };
 
 /*
@@ -179,10 +180,13 @@ struct cifsUidInfo {
 struct cifsSesInfo {
        struct list_head cifsSessionList;
        struct semaphore sesSem;
+#if 0
        struct cifsUidInfo *uidInfo;    /* pointer to user info */
+#endif
        struct TCP_Server_Info *server; /* pointer to server info */
        atomic_t inUse; /* # of mounts (tree connections) on this ses */
        enum statusEnum status;
+       unsigned overrideSecFlg;  /* if non-zero override global sec flags */
        __u16 ipc_tid;          /* special tid for connection to IPC share */
        __u16 flags;
        char *serverOS;         /* name of operating system underlying server */
@@ -194,7 +198,7 @@ struct cifsSesInfo {
        char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for 
                                TCP names - will ipv6 and sctp addresses fit? */
        char userName[MAX_USERNAME_SIZE + 1];
-       char domainName[MAX_USERNAME_SIZE + 1];
+       char * domainName;
        char * password;
 };
 /* session flags */
@@ -209,12 +213,12 @@ struct cifsTconInfo {
        struct list_head openFileList;
        struct semaphore tconSem;
        struct cifsSesInfo *ses;        /* pointer to session associated with */
-       char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */
+       char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
        char *nativeFileSystem;
        __u16 tid;              /* The 2 byte tree id */
        __u16 Flags;            /* optional support bits */
        enum statusEnum tidStatus;
-       atomic_t useCount;      /* how many mounts (explicit or implicit) to this share */
+       atomic_t useCount;      /* how many explicit/implicit mounts to share */
 #ifdef CONFIG_CIFS_STATS
        atomic_t num_smbs_sent;
        atomic_t num_writes;
@@ -254,7 +258,7 @@ struct cifsTconInfo {
        spinlock_t stat_lock;
 #endif /* CONFIG_CIFS_STATS */
        FILE_SYSTEM_DEVICE_INFO fsDevInfo;
-       FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo;  /* ok if file system name truncated */
+       FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
        FILE_SYSTEM_UNIX_INFO fsUnixInfo;
        unsigned retry:1;
        unsigned nocase:1;
@@ -305,7 +309,6 @@ struct cifsFileInfo {
        atomic_t wrtPending;   /* handle in use - defer close */
        struct semaphore fh_sem; /* prevents reopen race after dead ses*/
        char * search_resume_name; /* BB removeme BB */
-       unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
        struct cifs_search_info srch_inf;
 };
 
@@ -391,9 +394,9 @@ struct mid_q_entry {
        struct smb_hdr *resp_buf;       /* response buffer */
        int midState;   /* wish this were enum but can not pass to wait_event */
        __u8 command;   /* smb command code */
-       unsigned multiPart:1;   /* multiple responses to one SMB request */
        unsigned largeBuf:1;    /* if valid response, is pointer to large buf */
-       unsigned multiResp:1;   /* multiple trans2 responses for one request  */
+       unsigned multiRsp:1;   /* multiple trans2 responses for one request  */
+       unsigned multiEnd:1; /* both received */
 };
 
 struct oplock_q_entry {
@@ -430,15 +433,35 @@ struct dir_notify_req {
 #define   CIFS_LARGE_BUFFER     2
 #define   CIFS_IOVEC            4    /* array of response buffers */
 
-/* Type of session setup needed */
-#define   CIFS_PLAINTEXT       0
-#define   CIFS_LANMAN          1
-#define   CIFS_NTLM            2
-#define   CIFS_NTLMSSP_NEG     3
-#define   CIFS_NTLMSSP_AUTH    4
-#define   CIFS_SPNEGO_INIT     5
-#define   CIFS_SPNEGO_TARG     6
-
+/* Security Flags: indicate type of session setup needed */
+#define   CIFSSEC_MAY_SIGN     0x00001
+#define   CIFSSEC_MAY_NTLM     0x00002
+#define   CIFSSEC_MAY_NTLMV2   0x00004
+#define   CIFSSEC_MAY_KRB5     0x00008
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define   CIFSSEC_MAY_LANMAN   0x00010
+#define   CIFSSEC_MAY_PLNTXT   0x00020
+#endif /* weak passwords */
+#define   CIFSSEC_MAY_SEAL     0x00040 /* not supported yet */
+
+#define   CIFSSEC_MUST_SIGN    0x01001
+/* note that only one of the following can be set so the
+result of setting MUST flags more than once will be to
+require use of the stronger protocol */
+#define   CIFSSEC_MUST_NTLM    0x02002
+#define   CIFSSEC_MUST_NTLMV2  0x04004
+#define   CIFSSEC_MUST_KRB5    0x08008
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define   CIFSSEC_MUST_LANMAN  0x10010
+#define   CIFSSEC_MUST_PLNTXT  0x20020
+#define   CIFSSEC_MASK          0x37037 /* current flags supported if weak */
+#else    
+#define          CIFSSEC_MASK          0x07007 /* flags supported if no weak config */
+#endif /* WEAK_PW_HASH */
+#define   CIFSSEC_MUST_SEAL    0x40040 /* not supported yet */
+
+#define   CIFSSEC_DEF  CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2
+#define   CIFSSEC_MAX  CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2
 /*
  *****************************************************************
  * All constants go here
@@ -500,16 +523,16 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;  /* protects list inserts on 3 above */
 GLOBAL_EXTERN struct list_head GlobalOplock_Q;
 
 GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */
-GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */
+GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;/* DirNotify response queue */
 
 /*
  * Global transaction id (XID) information
  */
 GLOBAL_EXTERN unsigned int GlobalCurrentXid;   /* protected by GlobalMid_Sem */
-GLOBAL_EXTERN unsigned int GlobalTotalActiveXid;       /* prot by GlobalMid_Sem */
+GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */
 GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
-GLOBAL_EXTERN spinlock_t GlobalMid_Lock;  /* protects above and list operations */
-                                       /* on midQ entries */
+GLOBAL_EXTERN spinlock_t GlobalMid_Lock;  /* protects above & list operations */
+                                         /* on midQ entries */
 GLOBAL_EXTERN char Local_System_Name[15];
 
 /*
@@ -531,7 +554,7 @@ GLOBAL_EXTERN atomic_t smBufAllocCount;
 GLOBAL_EXTERN atomic_t midCount;
 
 /* Misc globals */
-GLOBAL_EXTERN unsigned int multiuser_mount;    /* if enabled allows new sessions
+GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
                                to be established on existing mount if we
                                have the uid/password or Kerberos credential 
                                or equivalent for current user */
@@ -540,8 +563,8 @@ GLOBAL_EXTERN unsigned int experimEnabled;
 GLOBAL_EXTERN unsigned int lookupCacheEnabled;
 GLOBAL_EXTERN unsigned int extended_security;  /* if on, session setup sent 
                                with more secure ntlmssp2 challenge/resp */
-GLOBAL_EXTERN unsigned int ntlmv2_support;  /* better optional password hash */
 GLOBAL_EXTERN unsigned int sign_CIFS_PDUs;  /* enable smb packet signing */
+GLOBAL_EXTERN unsigned int secFlags;
 GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
 GLOBAL_EXTERN unsigned int CIFSMaxBufSize;  /* max size not including hdr */
 GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
index b2233ac05bd2791f143a036fc95f313bb96bc13e..86239023545b2d65dd6bc7240df7c5d2b88f9614 100644 (file)
@@ -16,7 +16,7 @@
  *
  *   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 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #ifndef _CIFSPDU_H
 
 #include <net/sock.h>
 
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define LANMAN_PROT 0
+#define CIFS_PROT   1
+#else
 #define CIFS_PROT   0
-#define BAD_PROT    CIFS_PROT+1
+#endif
+#define POSIX_PROT  CIFS_PROT+1
+#define BAD_PROT 0xFFFF
 
 /* SMB command codes */
 /* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
 /*
  * Size of the session key (crypto key encrypted with the password
  */
-#define CIFS_SESSION_KEY_SIZE (24)
+#define CIFS_SESS_KEY_SIZE (24)
 
 /*
  * Maximum user name length
@@ -400,6 +406,29 @@ typedef struct negotiate_req {
        unsigned char DialectsArray[1];
 } __attribute__((packed)) NEGOTIATE_REQ;
 
+/* Dialect index is 13 for LANMAN */
+
+typedef struct lanman_neg_rsp {
+       struct smb_hdr hdr;     /* wct = 13 */
+       __le16 DialectIndex;
+       __le16 SecurityMode;
+       __le16 MaxBufSize;
+       __le16 MaxMpxCount;
+       __le16 MaxNumberVcs;
+       __le16 RawMode;
+       __le32 SessionKey;
+       __le32 ServerTime;
+       __le16 ServerTimeZone;
+       __le16 EncryptionKeyLength;
+       __le16 Reserved;
+       __u16  ByteCount;
+       unsigned char EncryptionKey[1];
+} __attribute__((packed)) LANMAN_NEG_RSP;
+
+#define READ_RAW_ENABLE 1
+#define WRITE_RAW_ENABLE 2
+#define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE)
+
 typedef struct negotiate_rsp {
        struct smb_hdr hdr;     /* wct = 17 */
        __le16 DialectIndex;
@@ -509,7 +538,7 @@ typedef union smb_com_session_setup_andx {
 /*      unsigned char  * NativeOS;      */
 /*     unsigned char  * NativeLanMan;  */
 /*      unsigned char  * PrimaryDomain; */
-       } __attribute__((packed)) resp;                 /* NTLM response format (with or without extended security */
+       } __attribute__((packed)) resp; /* NTLM response with or without extended sec*/
 
        struct {                /* request format */
                struct smb_hdr hdr;     /* wct = 10 */
@@ -520,8 +549,8 @@ typedef union smb_com_session_setup_andx {
                __le16 MaxMpxCount;
                __le16 VcNumber;
                __u32 SessionKey;
-               __le16 PassswordLength;
-               __u32 Reserved;
+               __le16 PasswordLength;
+               __u32 Reserved; /* encrypt key len and offset */
                __le16 ByteCount;
                unsigned char AccountPassword[1];       /* followed by */
                /* STRING AccountName */
@@ -543,6 +572,26 @@ typedef union smb_com_session_setup_andx {
        } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */
 } __attribute__((packed)) SESSION_SETUP_ANDX;
 
+/* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */
+
+struct ntlmssp2_name {
+       __le16 type;
+       __le16 length;
+/*     char   name[length]; */
+} __attribute__((packed));
+
+struct ntlmv2_resp {
+       char ntlmv2_hash[CIFS_ENCPWD_SIZE];
+       __le32 blob_signature;
+       __u32  reserved;
+       __le64  time;
+       __u64  client_chal; /* random */
+       __u32  reserved2;
+       struct ntlmssp2_name names[1];
+       /* array of name entries could follow ending in minimum 4 byte struct */
+} __attribute__((packed));
+
+
 #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
 
 /* Capabilities bits (for NTLM SessSetup request) */
@@ -573,7 +622,9 @@ typedef struct smb_com_tconx_req {
 } __attribute__((packed)) TCONX_REQ;
 
 typedef struct smb_com_tconx_rsp {
-       struct smb_hdr hdr;     /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */
+       struct smb_hdr hdr;     /* wct = 3 note that Win2000 has sent wct = 7
+                                in some cases on responses. Four unspecified
+                                words followed OptionalSupport */
        __u8 AndXCommand;
        __u8 AndXReserved;
        __le16 AndXOffset;
@@ -1323,6 +1374,9 @@ struct smb_t2_rsp {
 #define SMB_FILE_MAXIMUM_INFO           0x40d
 
 /* Find File infolevels */
+#define SMB_FIND_FILE_INFO_STANDARD       0x001
+#define SMB_FIND_FILE_QUERY_EA_SIZE       0x002
+#define SMB_FIND_FILE_QUERY_EAS_FROM_LIST 0x003
 #define SMB_FIND_FILE_DIRECTORY_INFO      0x101
 #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
 #define SMB_FIND_FILE_NAMES_INFO          0x103
@@ -1844,13 +1898,13 @@ typedef struct {
 typedef struct {
        __le32 DeviceType;
        __le32 DeviceCharacteristics;
-} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO;     /* device info, level 0x104 */
+} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
 
 typedef struct {
        __le32 Attributes;
        __le32 MaxPathNameComponentLength;
        __le32 FileSystemNameLen;
-       char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */
+       char FileSystemName[52]; /* do not have to save this - get subset? */
 } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO;
 
 /******************************************************************************/
@@ -1947,7 +2001,8 @@ typedef struct {
 
 struct file_allocation_info {
        __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
-} __attribute__((packed));     /* size used on disk, level 0x103 for set, 0x105 for query */
+} __attribute__((packed));     /* size used on disk, for level 0x103 for set,
+                                  0x105 for query */
 
 struct file_end_of_file_info {
        __le64 FileSize;                /* offset to end of file */
@@ -2054,7 +2109,7 @@ typedef struct {
        __le32 ExtFileAttributes;
        __le32 FileNameLength;
        char FileName[1];
-} __attribute__((packed)) FILE_DIRECTORY_INFO;   /* level 0x101 FF response data area */
+} __attribute__((packed)) FILE_DIRECTORY_INFO;   /* level 0x101 FF resp data */
 
 typedef struct {
        __le32 NextEntryOffset;
@@ -2069,7 +2124,7 @@ typedef struct {
        __le32 FileNameLength;
        __le32 EaSize; /* length of the xattrs */
        char FileName[1];
-} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO;   /* level 0x102 FF response data area */
+} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */
 
 typedef struct {
        __le32 NextEntryOffset;
@@ -2086,7 +2141,7 @@ typedef struct {
        __le32 Reserved;
        __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
        char FileName[1];
-} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO;   /* level 0x105 FF response data area */
+} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */
 
 typedef struct {
        __le32 NextEntryOffset;
@@ -2104,7 +2159,22 @@ typedef struct {
        __u8   Reserved;
        __u8   ShortName[12];
        char FileName[1];
-} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO;   /* level 0x104 FF response data area */
+} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */
+
+typedef struct {
+       __u32  ResumeKey;
+       __le16 CreationDate; /* SMB Date */
+       __le16 CreationTime; /* SMB Time */
+       __le16 LastAccessDate;
+       __le16 LastAccessTime;
+       __le16 LastWriteDate;
+       __le16 LastWriteTime;
+       __le32 DataSize; /* File Size (EOF) */
+       __le32 AllocationSize;
+       __le16 Attributes; /* verify not u32 */
+       __u8   FileNameLength;
+       char FileName[1];
+} __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */
 
 
 struct win_dev {
index 310ea2f0e0bfd27d6eacd91ffe0f695a0ca89322..a5ddc62d6fe6e2c09f4b70dcbf4f7a69a22c9b17 100644 (file)
@@ -64,14 +64,12 @@ extern int map_smb_to_linux_error(struct smb_hdr *smb);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
                            const struct cifsTconInfo *, int /* length of
                            fixed section (word count) in two byte units */);
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
                                struct cifsSesInfo *ses,
                                void ** request_buf);
 extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
-                            const int stage, int * pNTLMv2_flg,
+                            const int stage, 
                             const struct nls_table *nls_cp);
-#endif
 extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, 
                                                 struct cifsTconInfo *);
@@ -285,8 +283,14 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
 extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
        __u32 expected_sequence_number);
 extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
-extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
-extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * );
+extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, 
+                       const struct nls_table *);
+extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * );
+extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, 
+                            const struct nls_table *);
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key);
+#endif /* CIFS_WEAK_PW_HASH */
 extern int CIFSSMBCopy(int xid,
                        struct cifsTconInfo *source_tcon,
                        const char *fromName,
index 925881e00ff210e08822cc456337be1734f801d8..19678c575dfc4bcc786d158a20f56a450caccec1 100644 (file)
@@ -44,8 +44,11 @@ static struct {
        int index;
        char *name;
 } protocols[] = {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+       {LANMAN_PROT, "\2LM1.2X002"},
+#endif /* weak password hashing for legacy clients */
        {CIFS_PROT, "\2NT LM 0.12"}, 
-       {CIFS_PROT, "\2POSIX 2"},
+       {POSIX_PROT, "\2POSIX 2"},
        {BAD_PROT, "\2"}
 };
 #else
@@ -53,11 +56,29 @@ static struct {
        int index;
        char *name;
 } protocols[] = {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+       {LANMAN_PROT, "\2LM1.2X002"},
+#endif /* weak password hashing for legacy clients */
        {CIFS_PROT, "\2NT LM 0.12"}, 
        {BAD_PROT, "\2"}
 };
 #endif
 
+/* define the number of elements in the cifs dialect array */
+#ifdef CONFIG_CIFS_POSIX
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define CIFS_NUM_PROT 3
+#else
+#define CIFS_NUM_PROT 2
+#endif /* CIFS_WEAK_PW_HASH */
+#else /* not posix */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define CIFS_NUM_PROT 2
+#else
+#define CIFS_NUM_PROT 1
+#endif /* CONFIG_CIFS_WEAK_PW_HASH */
+#endif /* CIFS_POSIX */
+
 
 /* Mark as invalid, all open files on tree connections since they
    were closed when session to server was lost */
@@ -188,7 +209,6 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
        return rc;
 }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL  
 int
 small_smb_init_no_tc(const int smb_command, const int wct, 
                     struct cifsSesInfo *ses, void **request_buf)
@@ -214,7 +234,6 @@ small_smb_init_no_tc(const int smb_command, const int wct,
 
        return rc;
 }
-#endif  /* CONFIG_CIFS_EXPERIMENTAL */
 
 /* If the return code is zero, this function must fill in request_buf pointer */
 static int
@@ -322,7 +341,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
     /* potential retries of smb operations it turns out we can determine */
     /* from the mid flags when the request buffer can be resent without  */
     /* having to use a second distinct buffer for the response */
-       *response_buf = *request_buf; 
+       if(response_buf)
+               *response_buf = *request_buf; 
 
        header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
                        wct /*wct */ );
@@ -373,8 +393,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        NEGOTIATE_RSP *pSMBr;
        int rc = 0;
        int bytes_returned;
+       int i;
        struct TCP_Server_Info * server;
        u16 count;
+       unsigned int secFlags;
 
        if(ses->server)
                server = ses->server;
@@ -386,101 +408,200 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                      (void **) &pSMB, (void **) &pSMBr);
        if (rc)
                return rc;
+
+       /* if any of auth flags (ie not sign or seal) are overriden use them */
+       if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
+               secFlags = ses->overrideSecFlg;
+       else /* if override flags set only sign/seal OR them with global auth */
+               secFlags = extended_security | ses->overrideSecFlg;
+
+       cFYI(1,("secFlags 0x%x",secFlags));
+
        pSMB->hdr.Mid = GetNextMid(server);
        pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
-       if (extended_security)
+       if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-
-       count = strlen(protocols[0].name) + 1;
-       strncpy(pSMB->DialectsArray, protocols[0].name, 30);    
-    /* null guaranteed to be at end of source and target buffers anyway */
-
+       
+       count = 0;
+       for(i=0;i<CIFS_NUM_PROT;i++) {
+               strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
+               count += strlen(protocols[i].name) + 1;
+               /* null at end of source and target buffers anyway */
+       }
        pSMB->hdr.smb_buf_length += count;
        pSMB->ByteCount = cpu_to_le16(count);
 
        rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc == 0) {
-               server->secMode = pSMBr->SecurityMode;
-               if((server->secMode & SECMODE_USER) == 0)
-                       cFYI(1,("share mode security"));
-               server->secType = NTLM; /* BB override default for
-                                          NTLMv2 or kerberos v5 */
-               /* one byte - no need to convert this or EncryptionKeyLen
-                  from little endian */
-               server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
-               /* probably no need to store and check maxvcs */
-               server->maxBuf =
-                       min(le32_to_cpu(pSMBr->MaxBufferSize),
+       if (rc != 0) 
+               goto neg_err_exit;
+
+       cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
+       /* Check wct = 1 error case */
+       if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
+               /* core returns wct = 1, but we do not ask for core - otherwise
+               small wct just comes when dialect index is -1 indicating we 
+               could not negotiate a common dialect */
+               rc = -EOPNOTSUPP;
+               goto neg_err_exit;
+#ifdef CONFIG_CIFS_WEAK_PW_HASH 
+       } else if((pSMBr->hdr.WordCount == 13)
+                       && (pSMBr->DialectIndex == LANMAN_PROT)) {
+               struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
+
+               if((secFlags & CIFSSEC_MAY_LANMAN) || 
+                       (secFlags & CIFSSEC_MAY_PLNTXT))
+                       server->secType = LANMAN;
+               else {
+                       cERROR(1, ("mount failed weak security disabled"
+                                  " in /proc/fs/cifs/SecurityFlags"));
+                       rc = -EOPNOTSUPP;
+                       goto neg_err_exit;
+               }       
+               server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
+               server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+               server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
+                               (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+               GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
+               /* even though we do not use raw we might as well set this
+               accurately, in case we ever find a need for it */
+               if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
+                       server->maxRw = 0xFF00;
+                       server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
+               } else {
+                       server->maxRw = 0;/* we do not need to use raw anyway */
+                       server->capabilities = CAP_MPX_MODE;
+               }
+               server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
+
+               /* BB get server time for time conversions and add
+               code to use it and timezone since this is not UTC */    
+
+               if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+                       memcpy(server->cryptKey, rsp->EncryptionKey,
+                               CIFS_CRYPTO_KEY_SIZE);
+               } else if (server->secMode & SECMODE_PW_ENCRYPT) {
+                       rc = -EIO; /* need cryptkey unless plain text */
+                       goto neg_err_exit;
+               }
+
+               cFYI(1,("LANMAN negotiated"));
+               /* we will not end up setting signing flags - as no signing
+               was in LANMAN and server did not return the flags on */
+               goto signing_check;
+#else /* weak security disabled */
+       } else if(pSMBr->hdr.WordCount == 13) {
+               cERROR(1,("mount failed, cifs module not built "
+                         "with CIFS_WEAK_PW_HASH support"));
+                       rc = -EOPNOTSUPP;
+#endif /* WEAK_PW_HASH */
+               goto neg_err_exit;
+       } else if(pSMBr->hdr.WordCount != 17) {
+               /* unknown wct */
+               rc = -EOPNOTSUPP;
+               goto neg_err_exit;
+       }
+       /* else wct == 17 NTLM */
+       server->secMode = pSMBr->SecurityMode;
+       if((server->secMode & SECMODE_USER) == 0)
+               cFYI(1,("share mode security"));
+
+       if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+               if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
+#endif /* CIFS_WEAK_PW_HASH */
+                       cERROR(1,("Server requests plain text password"
+                                 " but client support disabled"));
+
+       if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
+               server->secType = NTLMv2;
+       else if(secFlags & CIFSSEC_MAY_NTLM)
+               server->secType = NTLM;
+       else if(secFlags & CIFSSEC_MAY_NTLMV2)
+               server->secType = NTLMv2;
+       /* else krb5 ... any others ... */
+
+       /* one byte, so no need to convert this or EncryptionKeyLen from
+          little endian */
+       server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+       /* probably no need to store and check maxvcs */
+       server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
                        (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
-               server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
-               cFYI(0, ("Max buf = %d", ses->server->maxBuf));
-               GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
-               server->capabilities = le32_to_cpu(pSMBr->Capabilities);
-               server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
-        /* BB with UTC do we ever need to be using srvr timezone? */
-               if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
-                       memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
-                              CIFS_CRYPTO_KEY_SIZE);
-               } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
-                          && (pSMBr->EncryptionKeyLength == 0)) {
-                       /* decode security blob */
-               } else
-                       rc = -EIO;
+       server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
+       cFYI(0, ("Max buf = %d", ses->server->maxBuf));
+       GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
+       server->capabilities = le32_to_cpu(pSMBr->Capabilities);
+       server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
+       if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+               memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
+                      CIFS_CRYPTO_KEY_SIZE);
+       } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
+                       && (pSMBr->EncryptionKeyLength == 0)) {
+               /* decode security blob */
+       } else if (server->secMode & SECMODE_PW_ENCRYPT) {
+               rc = -EIO; /* no crypt key only if plain text pwd */
+               goto neg_err_exit;
+       }
 
-               /* BB might be helpful to save off the domain of server here */
+       /* BB might be helpful to save off the domain of server here */
 
-               if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
-                       (server->capabilities & CAP_EXTENDED_SECURITY)) {
-                       count = pSMBr->ByteCount;
-                       if (count < 16)
-                               rc = -EIO;
-                       else if (count == 16) {
-                               server->secType = RawNTLMSSP;
-                               if (server->socketUseCount.counter > 1) {
-                                       if (memcmp
-                                               (server->server_GUID,
-                                               pSMBr->u.extended_response.
-                                               GUID, 16) != 0) {
-                                               cFYI(1, ("server UID changed"));
-                                               memcpy(server->
-                                                       server_GUID,
-                                                       pSMBr->u.
-                                                       extended_response.
-                                                       GUID, 16);
-                                       }
-                               } else
+       if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
+               (server->capabilities & CAP_EXTENDED_SECURITY)) {
+               count = pSMBr->ByteCount;
+               if (count < 16)
+                       rc = -EIO;
+               else if (count == 16) {
+                       server->secType = RawNTLMSSP;
+                       if (server->socketUseCount.counter > 1) {
+                               if (memcmp(server->server_GUID,
+                                          pSMBr->u.extended_response.
+                                          GUID, 16) != 0) {
+                                       cFYI(1, ("server UID changed"));
                                        memcpy(server->server_GUID,
-                                              pSMBr->u.extended_response.
-                                              GUID, 16);
-                       } else {
-                               rc = decode_negTokenInit(pSMBr->u.
-                                                        extended_response.
-                                                        SecurityBlob,
-                                                        count - 16,
-                                                        &server->secType);
-                               if(rc == 1) {
-                               /* BB Need to fill struct for sessetup here */
-                                       rc = -EOPNOTSUPP;
-                               } else {
-                                       rc = -EINVAL;
+                                               pSMBr->u.extended_response.GUID,
+                                               16);
                                }
+                       } else
+                               memcpy(server->server_GUID,
+                                      pSMBr->u.extended_response.GUID, 16);
+               } else {
+                       rc = decode_negTokenInit(pSMBr->u.extended_response.
+                                                SecurityBlob,
+                                                count - 16,
+                                                &server->secType);
+                       if(rc == 1) {
+                       /* BB Need to fill struct for sessetup here */
+                               rc = -EOPNOTSUPP;
+                       } else {
+                               rc = -EINVAL;
                        }
-               } else
-                       server->capabilities &= ~CAP_EXTENDED_SECURITY;
-               if(sign_CIFS_PDUs == FALSE) {        
-                       if(server->secMode & SECMODE_SIGN_REQUIRED)
-                               cERROR(1,
-                                ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
-                       server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-               } else if(sign_CIFS_PDUs == 1) {
-                       if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
-                               server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
                }
-                               
+       } else
+               server->capabilities &= ~CAP_EXTENDED_SECURITY;
+
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+signing_check:
+#endif
+       if(sign_CIFS_PDUs == FALSE) {        
+               if(server->secMode & SECMODE_SIGN_REQUIRED)
+                       cERROR(1,("Server requires "
+                                "/proc/fs/cifs/PacketSigningEnabled to be on"));
+               server->secMode &= 
+                       ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+       } else if(sign_CIFS_PDUs == 1) {
+               if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
+                       server->secMode &= 
+                               ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+       } else if(sign_CIFS_PDUs == 2) {
+               if((server->secMode & 
+                       (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
+                       cERROR(1,("signing required but server lacks support"));
+               }
        }
-       
+neg_err_exit:  
        cifs_buf_release(pSMB);
+
+       cFYI(1,("negprot rc %d",rc));
        return rc;
 }
 
@@ -2239,7 +2360,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
                        }
                        symlinkinfo[buflen] = 0; /* just in case so the caller
                                        does not go off the end of the buffer */
-                       cFYI(1,("readlink result - %s ",symlinkinfo));
+                       cFYI(1,("readlink result - %s",symlinkinfo));
                }
        }
 qreparse_out:
index bae1479318d10fc6fd34a141a564aeb49252ba80..876eb9ef85fecd83ae57042b2114cdd3b8355e00 100644 (file)
@@ -49,8 +49,6 @@
 
 static DECLARE_COMPLETION(cifsd_complete);
 
-extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
-                      unsigned char *p24);
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
                         unsigned char *p24);
 
@@ -70,6 +68,7 @@ struct smb_vol {
        gid_t linux_gid;
        mode_t file_mode;
        mode_t dir_mode;
+       unsigned secFlg;
        unsigned rw:1;
        unsigned retry:1;
        unsigned intr:1;
@@ -83,12 +82,7 @@ struct smb_vol {
        unsigned remap:1;   /* set to remap seven reserved chars in filenames */
        unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
        unsigned sfu_emul:1;
-       unsigned krb5:1;
-       unsigned ntlm:1;
-       unsigned ntlmv2:1;
        unsigned nullauth:1; /* attempt to authenticate with null user */
-       unsigned sign:1;
-       unsigned seal:1;     /* encrypt */
        unsigned nocase;     /* request case insensitive filenames */
        unsigned nobrl;      /* disable sending byte range locks to srv */
        unsigned int rsize;
@@ -369,21 +363,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        continue;
                if (bigbuf == NULL) {
                        bigbuf = cifs_buf_get();
-                       if(bigbuf == NULL) {
-                               cERROR(1,("No memory for large SMB response"));
+                       if (!bigbuf) {
+                               cERROR(1, ("No memory for large SMB response"));
                                msleep(3000);
                                /* retry will check if exiting */
                                continue;
                        }
-               } else if(isLargeBuf) {
-                       /* we are reusing a dirtry large buf, clear its start */
+               } else if (isLargeBuf) {
+                       /* we are reusing a dirty large buf, clear its start */
                        memset(bigbuf, 0, sizeof (struct smb_hdr));
                }
 
                if (smallbuf == NULL) {
                        smallbuf = cifs_small_buf_get();
-                       if(smallbuf == NULL) {
-                               cERROR(1,("No memory for SMB response"));
+                       if (!smallbuf) {
+                               cERROR(1, ("No memory for SMB response"));
                                msleep(1000);
                                /* retry will check if exiting */
                                continue;
@@ -403,12 +397,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                    kernel_recvmsg(csocket, &smb_msg,
                                 &iov, 1, 4, 0 /* BB see socket.h flags */);
 
-               if(server->tcpStatus == CifsExiting) {
+               if (server->tcpStatus == CifsExiting) {
                        break;
                } else if (server->tcpStatus == CifsNeedReconnect) {
-                       cFYI(1,("Reconnect after server stopped responding"));
+                       cFYI(1, ("Reconnect after server stopped responding"));
                        cifs_reconnect(server);
-                       cFYI(1,("call to reconnect done"));
+                       cFYI(1, ("call to reconnect done"));
                        csocket = server->ssocket;
                        continue;
                } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
@@ -417,15 +411,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                tcpStatus CifsNeedReconnect if server hung */
                        continue;
                } else if (length <= 0) {
-                       if(server->tcpStatus == CifsNew) {
-                               cFYI(1,("tcp session abend after SMBnegprot"));
+                       if (server->tcpStatus == CifsNew) {
+                               cFYI(1, ("tcp session abend after SMBnegprot"));
                                /* some servers kill the TCP session rather than
                                   returning an SMB negprot error, in which
                                   case reconnecting here is not going to help,
                                   and so simply return error to mount */
                                break;
                        }
-                       if(length == -EINTR) { 
+                       if (!try_to_freeze() && (length == -EINTR)) {
                                cFYI(1,("cifsd thread killed"));
                                break;
                        }
@@ -585,9 +579,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                                /* merge response - fix up 1st*/
                                                if(coalesce_t2(smb_buffer, 
                                                        mid_entry->resp_buf)) {
+                                                       mid_entry->multiRsp = 1;
                                                        break;
                                                } else {
                                                        /* all parts received */
+                                                       mid_entry->multiEnd = 1;
                                                        goto multi_t2_fnd; 
                                                }
                                        } else {
@@ -632,9 +628,14 @@ multi_t2_fnd:
                        wake_up_process(task_to_wake);
                } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
                    && (isMultiRsp == FALSE)) {                          
-                       cERROR(1, ("No task to wake, unknown frame rcvd!"));
+                       cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
                        cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
                                      sizeof(struct smb_hdr));
+#ifdef CONFIG_CIFS_DEBUG2
+                       cifs_dump_detail(smb_buffer);
+                       cifs_dump_mids(server);
+#endif /* CIFS_DEBUG2 */
+                       
                }
        } /* end while !EXITING */
 
@@ -784,7 +785,6 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 
        /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
        vol->rw = TRUE;
-       vol->ntlm = TRUE;
        /* default is always to request posix paths. */
        vol->posix_paths = 1;
 
@@ -915,30 +915,35 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                cERROR(1,("no security value specified"));
                                 continue;
                         } else if (strnicmp(value, "krb5i", 5) == 0) {
-                               vol->sign = 1;
-                               vol->krb5 = 1;
+                               vol->secFlg |= CIFSSEC_MAY_KRB5 | 
+                                       CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "krb5p", 5) == 0) {
-                               /* vol->seal = 1; 
-                                  vol->krb5 = 1; */
+                               /* vol->secFlg |= CIFSSEC_MUST_SEAL | 
+                                       CIFSSEC_MAY_KRB5; */ 
                                cERROR(1,("Krb5 cifs privacy not supported"));
                                return 1;
                        } else if (strnicmp(value, "krb5", 4) == 0) {
-                               vol->krb5 = 1;
+                               vol->secFlg |= CIFSSEC_MAY_KRB5;
                        } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
-                               vol->ntlmv2 = 1;
-                               vol->sign = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
+                                       CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "ntlmv2", 6) == 0) {
-                               vol->ntlmv2 = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
                        } else if (strnicmp(value, "ntlmi", 5) == 0) {
-                               vol->ntlm = 1;
-                               vol->sign = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLM |
+                                       CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "ntlm", 4) == 0) {
                                /* ntlm is default so can be turned off too */
-                               vol->ntlm = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLM;
                        } else if (strnicmp(value, "nontlm", 6) == 0) {
-                               vol->ntlm = 0;
+                               /* BB is there a better way to do this? */
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+                       } else if (strnicmp(value, "lanman", 6) == 0) {
+                                vol->secFlg |= CIFSSEC_MAY_LANMAN;
+#endif
                        } else if (strnicmp(value, "none", 4) == 0) {
-                               vol->nullauth = 1; 
+                               vol->nullauth = 1;
                         } else {
                                 cERROR(1,("bad security option: %s", value));
                                 return 1;
@@ -976,7 +981,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        }
                        /* BB are there cases in which a comma can be valid in
                        a domain name and need special handling? */
-                       if (strnlen(value, 65) < 65) {
+                       if (strnlen(value, 256) < 256) {
                                vol->domainname = value;
                                cFYI(1, ("Domain name set"));
                        } else {
@@ -1168,6 +1173,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        vol->no_psx_acl = 0;
                } else if (strnicmp(data, "noacl",5) == 0) {
                        vol->no_psx_acl = 1;
+               } else if (strnicmp(data, "sign",4) == 0) {
+                       vol->secFlg |= CIFSSEC_MUST_SIGN;
+/*             } else if (strnicmp(data, "seal",4) == 0) {
+                       vol->secFlg |= CIFSSEC_MUST_SEAL; */
                } else if (strnicmp(data, "direct",6) == 0) {
                        vol->direct_io = 1;
                } else if (strnicmp(data, "forcedirectio",13) == 0) {
@@ -1762,11 +1771,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        if (volume_info.username)
                                strncpy(pSesInfo->userName,
                                        volume_info.username,MAX_USERNAME_SIZE);
-                       if (volume_info.domainname)
-                               strncpy(pSesInfo->domainName,
-                                       volume_info.domainname,MAX_USERNAME_SIZE);
+                       if (volume_info.domainname) {
+                               int len = strlen(volume_info.domainname);
+                               pSesInfo->domainName = 
+                                       kmalloc(len + 1, GFP_KERNEL);
+                               if(pSesInfo->domainName)
+                                       strcpy(pSesInfo->domainName,
+                                               volume_info.domainname);
+                       }
                        pSesInfo->linux_uid = volume_info.linux_uid;
+                       pSesInfo->overrideSecFlg = volume_info.secFlg;
                        down(&pSesInfo->sesSem);
+                       /* BB FIXME need to pass vol->secFlgs BB */
                        rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
                        up(&pSesInfo->sesSem);
                        if(!rc)
@@ -1980,7 +1996,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 
 static int
 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-             char session_key[CIFS_SESSION_KEY_SIZE],
+             char session_key[CIFS_SESS_KEY_SIZE],
              const struct nls_table *nls_codepage)
 {
        struct smb_hdr *smb_buffer;
@@ -2038,15 +2054,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
 
        pSMB->req_no_secext.CaseInsensitivePasswordLength = 
-               cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+               cpu_to_le16(CIFS_SESS_KEY_SIZE);
 
        pSMB->req_no_secext.CaseSensitivePasswordLength =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
        bcc_ptr = pByteArea(smb_buffer);
-       memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
-       memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
                if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
@@ -2054,7 +2070,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                        bcc_ptr++;
                }
                if(user == NULL)
-                       bytes_returned = 0; /* skill null user */
+                       bytes_returned = 0; /* skip null user */
                else
                        bytes_returned =
                                cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
@@ -2162,8 +2178,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                if (remaining_words > 0) {
                                        len = UniStrnlen((wchar_t *)bcc_ptr,
                                                         remaining_words-1);
-                                       if(ses->serverNOS)
-                                               kfree(ses->serverNOS);
+                                       kfree(ses->serverNOS);
                                        ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
                                        if(ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
@@ -2203,12 +2218,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        /* if these kcallocs fail not much we
                                           can do, but better to not fail the
                                           sesssetup itself */
-                                       if(ses->serverDomain)
-                                               kfree(ses->serverDomain);
+                                       kfree(ses->serverDomain);
                                        ses->serverDomain =
                                            kzalloc(2, GFP_KERNEL);
-                                       if(ses->serverNOS)
-                                               kfree(ses->serverNOS);
+                                       kfree(ses->serverNOS);
                                        ses->serverNOS =
                                            kzalloc(2, GFP_KERNEL);
                                }
@@ -2217,8 +2230,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                if (((long) bcc_ptr + len) - (long)
                                    pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
-                                       if(ses->serverOS)
-                                               kfree(ses->serverOS);
+                                       kfree(ses->serverOS);
                                        ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverOS == NULL)
                                                goto sesssetup_nomem;
@@ -2229,8 +2241,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
-                                       if(ses->serverNOS)
-                                               kfree(ses->serverNOS);
+                                       kfree(ses->serverNOS);
                                        ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
@@ -2273,292 +2284,6 @@ sesssetup_nomem:        /* do not return an error on nomem for the info strings,
        return rc;
 }
 
-static int
-CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-               char *SecurityBlob,int SecurityBlobLength,
-               const struct nls_table *nls_codepage)
-{
-       struct smb_hdr *smb_buffer;
-       struct smb_hdr *smb_buffer_response;
-       SESSION_SETUP_ANDX *pSMB;
-       SESSION_SETUP_ANDX *pSMBr;
-       char *bcc_ptr;
-       char *user;
-       char *domain;
-       int rc = 0;
-       int remaining_words = 0;
-       int bytes_returned = 0;
-       int len;
-       __u32 capabilities;
-       __u16 count;
-
-       cFYI(1, ("In spnego sesssetup "));
-       if(ses == NULL)
-               return -EINVAL;
-       user = ses->userName;
-       domain = ses->domainName;
-
-       smb_buffer = cifs_buf_get();
-       if (smb_buffer == NULL) {
-               return -ENOMEM;
-       }
-       smb_buffer_response = smb_buffer;
-       pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
-
-       /* send SMBsessionSetup here */
-       header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
-                       NULL /* no tCon exists yet */ , 12 /* wct */ );
-
-       smb_buffer->Mid = GetNextMid(ses->server);
-       pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       pSMB->req.AndXCommand = 0xFF;
-       if(ses->server->maxBuf > 64*1024)
-               ses->server->maxBuf = (64*1023);
-       pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
-       pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
-
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-               smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
-       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
-           CAP_EXTENDED_SECURITY;
-       if (ses->capabilities & CAP_UNICODE) {
-               smb_buffer->Flags2 |= SMBFLG2_UNICODE;
-               capabilities |= CAP_UNICODE;
-       }
-       if (ses->capabilities & CAP_STATUS32) {
-               smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
-               capabilities |= CAP_STATUS32;
-       }
-       if (ses->capabilities & CAP_DFS) {
-               smb_buffer->Flags2 |= SMBFLG2_DFS;
-               capabilities |= CAP_DFS;
-       }
-       pSMB->req.Capabilities = cpu_to_le32(capabilities);
-
-       pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
-       bcc_ptr = pByteArea(smb_buffer);
-       memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
-       bcc_ptr += SecurityBlobLength;
-
-       if (ses->capabilities & CAP_UNICODE) {
-               if ((long) bcc_ptr % 2) {       /* must be word aligned for Unicode strings */
-                       *bcc_ptr = 0;
-                       bcc_ptr++;
-               }
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;  /* convert num of 16 bit words to bytes */
-               bcc_ptr += 2;   /* trailing null */
-               if (domain == NULL)
-                       bytes_returned =
-                           cifs_strtoUCS((__le16 *) bcc_ptr,
-                                         "CIFS_LINUX_DOM", 32, nls_codepage);
-               else
-                       bytes_returned =
-                           cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
-                                         nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
-                                 32, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
-                                 nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
-                                 64, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-       } else {
-               strncpy(bcc_ptr, user, 200);
-               bcc_ptr += strnlen(user, 200);
-               *bcc_ptr = 0;
-               bcc_ptr++;
-               if (domain == NULL) {
-                       strcpy(bcc_ptr, "CIFS_LINUX_DOM");
-                       bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
-               } else {
-                       strncpy(bcc_ptr, domain, 64);
-                       bcc_ptr += strnlen(domain, 64);
-                       *bcc_ptr = 0;
-                       bcc_ptr++;
-               }
-               strcpy(bcc_ptr, "Linux version ");
-               bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, system_utsname.release);
-               bcc_ptr += strlen(system_utsname.release) + 1;
-               strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
-               bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
-       }
-       count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
-       smb_buffer->smb_buf_length += count;
-       pSMB->req.ByteCount = cpu_to_le16(count);
-
-       rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
-                        &bytes_returned, 1);
-       if (rc) {
-/*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
-       } else if ((smb_buffer_response->WordCount == 3)
-                  || (smb_buffer_response->WordCount == 4)) {
-               __u16 action = le16_to_cpu(pSMBr->resp.Action);
-               __u16 blob_len =
-                   le16_to_cpu(pSMBr->resp.SecurityBlobLength);
-               if (action & GUEST_LOGIN)
-                       cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
-               if (ses) {
-                       ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
-                       cFYI(1, ("UID = %d ", ses->Suid));
-                       bcc_ptr = pByteArea(smb_buffer_response);       /* response can have either 3 or 4 word count - Samba sends 3 */
-
-                       /* BB Fix below to make endian neutral !! */
-
-                       if ((pSMBr->resp.hdr.WordCount == 3)
-                           || ((pSMBr->resp.hdr.WordCount == 4)
-                               && (blob_len <
-                                   pSMBr->resp.ByteCount))) {
-                               if (pSMBr->resp.hdr.WordCount == 4) {
-                                       bcc_ptr +=
-                                           blob_len;
-                                       cFYI(1,
-                                            ("Security Blob Length %d ",
-                                             blob_len));
-                               }
-
-                               if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
-                                       if ((long) (bcc_ptr) % 2) {
-                                               remaining_words =
-                                                   (BCC(smb_buffer_response)
-                                                    - 1) / 2;
-                                               bcc_ptr++;      /* Unicode strings must be word aligned */
-                                       } else {
-                                               remaining_words =
-                                                   BCC
-                                                   (smb_buffer_response) / 2;
-                                       }
-                                       len =
-                                           UniStrnlen((wchar_t *) bcc_ptr,
-                                                      remaining_words - 1);
-/* We look for obvious messed up bcc or strings in response so we do not go off
-   the end since (at least) WIN2K and Windows XP have a major bug in not null
-   terminating last Unicode string in response  */
-                                       if(ses->serverOS)
-                                               kfree(ses->serverOS);
-                                       ses->serverOS =
-                                           kzalloc(2 * (len + 1), GFP_KERNEL);
-                                       cifs_strfromUCS_le(ses->serverOS,
-                                                          (__le16 *)
-                                                          bcc_ptr, len,
-                                                          nls_codepage);
-                                       bcc_ptr += 2 * (len + 1);
-                                       remaining_words -= len + 1;
-                                       ses->serverOS[2 * len] = 0;
-                                       ses->serverOS[1 + (2 * len)] = 0;
-                                       if (remaining_words > 0) {
-                                               len = UniStrnlen((wchar_t *)bcc_ptr,
-                                                                remaining_words
-                                                                - 1);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
-                                               ses->serverNOS =
-                                                   kzalloc(2 * (len + 1),
-                                                           GFP_KERNEL);
-                                               cifs_strfromUCS_le(ses->serverNOS,
-                                                                  (__le16 *)bcc_ptr,
-                                                                  len,
-                                                                  nls_codepage);
-                                               bcc_ptr += 2 * (len + 1);
-                                               ses->serverNOS[2 * len] = 0;
-                                               ses->serverNOS[1 + (2 * len)] = 0;
-                                               remaining_words -= len + 1;
-                                               if (remaining_words > 0) {
-                                                       len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
-                     /* last string not null terminated (e.g.Windows XP/2000) */
-                                                       if(ses->serverDomain)
-                                                               kfree(ses->serverDomain);
-                                                       ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
-                                                       cifs_strfromUCS_le(ses->serverDomain,
-                                                            (__le16 *)bcc_ptr, 
-                                                            len, nls_codepage);
-                                                       bcc_ptr += 2*(len+1);
-                                                       ses->serverDomain[2*len] = 0;
-                                                       ses->serverDomain[1+(2*len)] = 0;
-                                               } /* else no more room so create dummy domain string */
-                                               else {
-                                                       if(ses->serverDomain)
-                                                               kfree(ses->serverDomain);
-                                                       ses->serverDomain =
-                                                           kzalloc(2,GFP_KERNEL);
-                                               }
-                                       } else {/* no room use dummy domain&NOS */
-                                               if(ses->serverDomain)
-                                                       kfree(ses->serverDomain);
-                                               ses->serverDomain = kzalloc(2, GFP_KERNEL);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
-                                               ses->serverNOS = kzalloc(2, GFP_KERNEL);
-                                       }
-                               } else {        /* ASCII */
-
-                                       len = strnlen(bcc_ptr, 1024);
-                                       if (((long) bcc_ptr + len) - (long)
-                                           pByteArea(smb_buffer_response)
-                                           <= BCC(smb_buffer_response)) {
-                                               if(ses->serverOS)
-                                                       kfree(ses->serverOS);
-                                               ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
-                                               strncpy(ses->serverOS, bcc_ptr, len);
-
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0; /* null terminate the string */
-                                               bcc_ptr++;
-
-                                               len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
-                                               ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
-                                               strncpy(ses->serverNOS, bcc_ptr, len);
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0;
-                                               bcc_ptr++;
-
-                                               len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverDomain)
-                                                       kfree(ses->serverDomain);
-                                               ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
-                                               strncpy(ses->serverDomain, bcc_ptr, len);
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0;
-                                               bcc_ptr++;
-                                       } else
-                                               cFYI(1,
-                                                    ("Variable field of length %d extends beyond end of smb ",
-                                                     len));
-                               }
-                       } else {
-                               cERROR(1,
-                                      (" Security Blob Length extends beyond end of SMB"));
-                       }
-               } else {
-                       cERROR(1, ("No session structure passed in."));
-               }
-       } else {
-               cERROR(1,
-                      (" Invalid Word count %d: ",
-                       smb_buffer_response->WordCount));
-               rc = -EIO;
-       }
-
-       if (smb_buffer)
-               cifs_buf_release(smb_buffer);
-
-       return rc;
-}
-
 static int
 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                              struct cifsSesInfo *ses, int * pNTLMv2_flag,
@@ -2635,8 +2360,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
            /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
        if(sign_CIFS_PDUs)
                negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
-       if(ntlmv2_support)
-               negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
+/*     if(ntlmv2_support)
+               negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
        /* setup pointers to domain name and workstation name */
        bcc_ptr += SecurityBlobLength;
 
@@ -2783,8 +2508,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                                 bcc_ptr,
                                                                 remaining_words
                                                                 - 1);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
@@ -2802,8 +2526,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                if (remaining_words > 0) {
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
-                                                       if(ses->serverDomain)
-                                                               kfree(ses->serverDomain);
+                                                       kfree(ses->serverDomain);
                                                        ses->serverDomain =
                                                            kzalloc(2 *
                                                                    (len +
@@ -2822,19 +2545,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
                                                else {
-                                                       if(ses->serverDomain)
-                                                               kfree(ses->serverDomain);
+                                                       kfree(ses->serverDomain);
                                                        ses->serverDomain =
                                                            kzalloc(2,
                                                                    GFP_KERNEL);
                                                }
                                        } else {        /* no room so create dummy domain and NOS string */
-                                               if(ses->serverDomain);
-                                                       kfree(ses->serverDomain);
+                                               kfree(ses->serverDomain);
                                                ses->serverDomain =
                                                    kzalloc(2, GFP_KERNEL);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2, GFP_KERNEL);
                                        }
@@ -2856,8 +2576,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(len + 1,
                                                            GFP_KERNEL);
@@ -2867,8 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverDomain)
-                                                       kfree(ses->serverDomain);
+                                               kfree(ses->serverDomain);
                                                ses->serverDomain =
                                                    kzalloc(len + 1,
                                                            GFP_KERNEL);
@@ -2994,14 +2712,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        SecurityBlob->LmChallengeResponse.Buffer = 0;
 
        SecurityBlob->NtChallengeResponse.Length =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.MaximumLength =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
-       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
+       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.Buffer =
            cpu_to_le32(SecurityBlobLength);
-       SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
+       SecurityBlobLength += CIFS_SESS_KEY_SIZE;
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
                if (domain == NULL) {
@@ -3190,8 +2908,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 bcc_ptr,
                                                                 remaining_words
                                                                 - 1);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
@@ -3244,8 +2961,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                if(ses->serverDomain)
                                                        kfree(ses->serverDomain);
                                                ses->serverDomain = kzalloc(2, GFP_KERNEL);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS = kzalloc(2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
@@ -3263,8 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               if(ses->serverNOS)
-                                                       kfree(ses->serverNOS);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);  
                                                bcc_ptr += len;
@@ -3340,22 +3055,33 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        bcc_ptr = &pSMB->Password[0];
        if((ses->server->secMode) & SECMODE_USER) {
                pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
+               *bcc_ptr = 0; /* password is null byte */
                bcc_ptr++;              /* skip password */
+               /* already aligned so no need to do it below */
        } else {
-               pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+               pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
                /* BB FIXME add code to fail this if NTLMv2 or Kerberos
                   specified as required (when that support is added to
                   the vfs in the future) as only NTLM or the much
-                  weaker LANMAN (which we do not send) is accepted
+                  weaker LANMAN (which we do not send by default) is accepted
                   by Samba (not sure whether other servers allow
                   NTLMv2 password here) */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+               if((extended_security & CIFSSEC_MAY_LANMAN) && 
+                       (ses->server->secType == LANMAN))
+                       calc_lanman_hash(ses, bcc_ptr);
+               else
+#endif /* CIFS_WEAK_PW_HASH */
                SMBNTencrypt(ses->password,
                             ses->server->cryptKey,
                             bcc_ptr);
 
-               bcc_ptr += CIFS_SESSION_KEY_SIZE;
-               *bcc_ptr = 0;
-               bcc_ptr++; /* align */
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               if(ses->capabilities & CAP_UNICODE) {
+                       /* must align unicode strings */
+                       *bcc_ptr = 0; /* null byte password */
+                       bcc_ptr++;
+               }
        }
 
        if(ses->server->secMode & 
@@ -3429,7 +3155,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                        }
                        /* else do not bother copying these informational fields */
                }
-               tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+               if(smb_buffer_response->WordCount == 3)
+                       tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+               else
+                       tcon->Flags = 0;
                cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
        } else if ((rc == 0) && tcon == NULL) {
         /* all we need to save for IPC$ connection */
@@ -3494,7 +3223,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                           struct nls_table * nls_info)
 {
        int rc = 0;
-       char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
+       char ntlm_session_key[CIFS_SESS_KEY_SIZE];
        int ntlmv2_flag = FALSE;
        int first_time = 0;
 
@@ -3526,20 +3255,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
                        pSesInfo->server->timeZone));
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-               if(experimEnabled > 1)
-                       rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */,
-                                           &ntlmv2_flag, nls_info);    
-               else
-#endif
-               if (extended_security
+               if(experimEnabled < 2)
+                       rc = CIFS_SessSetup(xid, pSesInfo,
+                                           first_time, nls_info);
+               else if (extended_security
                                && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
                                && (pSesInfo->server->secType == NTLMSSP)) {
-                       cFYI(1, ("New style sesssetup"));
-                       rc = CIFSSpnegoSessSetup(xid, pSesInfo,
-                               NULL /* security blob */, 
-                               0 /* blob length */,
-                               nls_info);
+                       rc = -EOPNOTSUPP;
                } else if (extended_security
                           && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
                           && (pSesInfo->server->secType == RawNTLMSSP)) {
index 82315edc77d7daaaaaca6865ca44e4946807190c..ba4cbe9b0684dd0a6ae66d65f8486462ab80e778 100644 (file)
@@ -113,7 +113,7 @@ cifs_bp_rename_retry:
        full_path[namelen+2] = 0;
 BB remove above eight lines BB */
 
-/* Inode operations in similar order to how they appear in the Linux file fs.h */
+/* Inode operations in similar order to how they appear in Linux file fs.h */
 
 int
 cifs_create(struct inode *inode, struct dentry *direntry, int mode,
@@ -178,11 +178,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                FreeXid(xid);
                return -ENOMEM;
        }
-
-       rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
+       if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) 
+               rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
                         desiredAccess, CREATE_NOT_DIR,
                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       else
+               rc = -EIO; /* no NT SMB support fall into legacy open below */
+
        if(rc == -EIO) {
                /* old server, retry the open legacy style */
                rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
@@ -191,7 +194,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        } 
        if (rc) {
-               cFYI(1, ("cifs_create returned 0x%x ", rc));
+               cFYI(1, ("cifs_create returned 0x%x", rc));
        } else {
                /* If Open reported that we actually created a file
                then we now have to set the mode if possible */
@@ -369,6 +372,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                                         cifs_sb->mnt_cifs_flags & 
                                            CIFS_MOUNT_MAP_SPECIAL_CHR);
 
+                       /* BB FIXME - add handling for backlevel servers
+                          which need legacy open and check for all
+                          calls to SMBOpen for fallback to 
+                          SMBLeagcyOpen */
                        if(!rc) {
                                /* BB Do not bother to decode buf since no
                                   local inode yet to put timestamps in,
index 633a938113287f2d0a75c6ba58953e800b755747..d91a3d44e9e30ce1f36b67b650482212355d8629 100644 (file)
@@ -91,14 +91,14 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
        if(full_path == NULL) {
                rc = -ENOMEM;
        } else {
-               cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */
+               cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg));
                rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, 
                        GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
                        &netfid, &oplock,NULL, cifs_sb->local_nls,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
                /* BB fixme - add this handle to a notify handle list */
                if(rc) {
-                       cERROR(1,("Could not open directory for notify"));  /* BB remove BB */
+                       cFYI(1,("Could not open directory for notify"));
                } else {
                        filter = convert_to_cifs_notify_flags(arg);
                        if(filter != 0) {
index b4a18c1cab0a878dca81359c032a8f8b7f2bf83b..5861eb42e6260135ff491f95512e961e60c3e11a 100644 (file)
@@ -110,7 +110,6 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
                         &pCifsInode->openFileList);
        }
        write_unlock(&GlobalSMBSeslock);
-       write_unlock(&file->f_owner.lock);
        if (pCifsInode->clientCanCacheRead) {
                /* we have the inode open somewhere else
                   no need to discard cache data */
@@ -201,7 +200,7 @@ int cifs_open(struct inode *inode, struct file *file)
                } else {
                        if (file->f_flags & O_EXCL)
                                cERROR(1, ("could not find file instance for "
-                                          "new file %p ", file));
+                                          "new file %p", file));
                }
        }
 
@@ -260,10 +259,15 @@ int cifs_open(struct inode *inode, struct file *file)
                rc = -ENOMEM;
                goto out;
        }
-       rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
-                        CREATE_NOT_DIR, &netfid, &oplock, buf,
+
+       if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
+               rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, 
+                        desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
                                 & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       else
+               rc = -EIO; /* no NT SMB support fall into legacy open below */
+
        if (rc == -EIO) {
                /* Old server, try legacy style OpenX */
                rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
@@ -272,7 +276,7 @@ int cifs_open(struct inode *inode, struct file *file)
                                & CIFS_MOUNT_MAP_SPECIAL_CHR);
        }
        if (rc) {
-               cFYI(1, ("cifs_open returned 0x%x ", rc));
+               cFYI(1, ("cifs_open returned 0x%x", rc));
                goto out;
        }
        file->private_data =
@@ -282,7 +286,6 @@ int cifs_open(struct inode *inode, struct file *file)
                goto out;
        }
        pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
-       write_lock(&file->f_owner.lock);
        write_lock(&GlobalSMBSeslock);
        list_add(&pCifsFile->tlist, &pTcon->openFileList);
 
@@ -293,7 +296,6 @@ int cifs_open(struct inode *inode, struct file *file)
                                            &oplock, buf, full_path, xid);
        } else {
                write_unlock(&GlobalSMBSeslock);
-               write_unlock(&file->f_owner.lock);
        }
 
        if (oplock & CIFS_CREATE_ACTION) {           
@@ -409,8 +411,8 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc) {
                up(&pCifsFile->fh_sem);
-               cFYI(1, ("cifs_open returned 0x%x ", rc));
-               cFYI(1, ("oplock: %d ", oplock));
+               cFYI(1, ("cifs_open returned 0x%x", rc));
+               cFYI(1, ("oplock: %d", oplock));
        } else {
                pCifsFile->netfid = netfid;
                pCifsFile->invalidHandle = FALSE;
@@ -472,7 +474,6 @@ int cifs_close(struct inode *inode, struct file *file)
        pTcon = cifs_sb->tcon;
        if (pSMBFile) {
                pSMBFile->closePend = TRUE;
-               write_lock(&file->f_owner.lock);
                if (pTcon) {
                        /* no sense reconnecting to close a file that is
                           already closed */
@@ -487,23 +488,18 @@ int cifs_close(struct inode *inode, struct file *file)
                                        the struct would be in each open file,
                                        but this should give enough time to 
                                        clear the socket */
-                                       write_unlock(&file->f_owner.lock);
                                        cERROR(1,("close with pending writes"));
                                        msleep(timeout);
-                                       write_lock(&file->f_owner.lock);
                                        timeout *= 4;
                                } 
-                               write_unlock(&file->f_owner.lock);
                                rc = CIFSSMBClose(xid, pTcon,
                                                  pSMBFile->netfid);
-                               write_lock(&file->f_owner.lock);
                        }
                }
                write_lock(&GlobalSMBSeslock);
                list_del(&pSMBFile->flist);
                list_del(&pSMBFile->tlist);
                write_unlock(&GlobalSMBSeslock);
-               write_unlock(&file->f_owner.lock);
                kfree(pSMBFile->search_resume_name);
                kfree(file->private_data);
                file->private_data = NULL;
@@ -531,7 +527,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
            (struct cifsFileInfo *)file->private_data;
        char *ptmp;
 
-       cFYI(1, ("Closedir inode = 0x%p with ", inode));
+       cFYI(1, ("Closedir inode = 0x%p", inode));
 
        xid = GetXid();
 
@@ -605,7 +601,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
        }
        if (pfLock->fl_flags & FL_ACCESS)
                cFYI(1, ("Process suspended by mandatory locking - "
-                        "not implemented yet "));
+                        "not implemented yet"));
        if (pfLock->fl_flags & FL_LEASE)
                cFYI(1, ("Lease on file - not implemented yet"));
        if (pfLock->fl_flags & 
@@ -1375,7 +1371,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
 
        xid = GetXid();
 
-       cFYI(1, ("Sync file - name: %s datasync: 0x%x ", 
+       cFYI(1, ("Sync file - name: %s datasync: 0x%x", 
                dentry->d_name.name, datasync));
        
        rc = filemap_fdatawrite(inode->i_mapping);
@@ -1404,7 +1400,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
 /*     fill in rpages then 
        result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
 
-/*     cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
+/*     cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
 
 #if 0
        if (rc < 0)
@@ -1836,7 +1832,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
        if (rc < 0)
                goto io_error;
        else
-               cFYI(1, ("Bytes read %d ",rc));
+               cFYI(1, ("Bytes read %d",rc));
                                                                                                                            
        file->f_dentry->d_inode->i_atime =
                current_fs_time(file->f_dentry->d_inode->i_sb);
@@ -1946,7 +1942,7 @@ static int cifs_prepare_write(struct file *file, struct page *page,
        return 0;
 }
 
-struct address_space_operations cifs_addr_ops = {
+const struct address_space_operations cifs_addr_ops = {
        .readpage = cifs_readpage,
        .readpages = cifs_readpages,
        .writepage = cifs_writepage,
@@ -1957,3 +1953,19 @@ struct address_space_operations cifs_addr_ops = {
        /* .sync_page = cifs_sync_page, */
        /* .direct_IO = */
 };
+
+/*
+ * cifs_readpages requires the server to support a buffer large enough to
+ * contain the header plus one complete page of data.  Otherwise, we need
+ * to leave cifs_readpages out of the address space operations.
+ */
+const struct address_space_operations cifs_addr_ops_smallbuf = {
+       .readpage = cifs_readpage,
+       .writepage = cifs_writepage,
+       .writepages = cifs_writepages,
+       .prepare_write = cifs_prepare_write,
+       .commit_write = cifs_commit_write,
+       .set_page_dirty = __set_page_dirty_nobuffers,
+       /* .sync_page = cifs_sync_page, */
+       /* .direct_IO = */
+};
index 4093764ef461e1797ac5e7403a238c3c12891ea3..b88147c1dc27f0df435b6251376a73b7dfc531cb 100644 (file)
@@ -41,7 +41,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
        char *tmp_path;
 
        pTcon = cifs_sb->tcon;
-       cFYI(1, ("Getting info on %s ", search_path));
+       cFYI(1, ("Getting info on %s", search_path));
        /* could have done a find first instead but this returns more info */
        rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
                                  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
@@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                inode = *pinode;
                cifsInfo = CIFS_I(inode);
 
-               cFYI(1, ("Old time %ld ", cifsInfo->time));
+               cFYI(1, ("Old time %ld", cifsInfo->time));
                cifsInfo->time = jiffies;
-               cFYI(1, ("New time %ld ", cifsInfo->time));
+               cFYI(1, ("New time %ld", cifsInfo->time));
                /* this is ok to set on every inode revalidate */
                atomic_set(&cifsInfo->inUse,1);
 
@@ -180,11 +180,12 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                        else /* not direct, send byte range locks */ 
                                inode->i_fop = &cifs_file_ops;
 
-                       inode->i_data.a_ops = &cifs_addr_ops;
                        /* check if server can support readpages */
                        if(pTcon->ses->server->maxBuf < 
-                           4096 + MAX_CIFS_HDR_SIZE)
-                               inode->i_data.a_ops->readpages = NULL;
+                           PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
+                               inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+                       else
+                               inode->i_data.a_ops = &cifs_addr_ops;
                } else if (S_ISDIR(inode->i_mode)) {
                        cFYI(1, ("Directory inode"));
                        inode->i_op = &cifs_dir_inode_ops;
@@ -421,23 +422,23 @@ int cifs_get_inode_info(struct inode **pinode,
                inode = *pinode;
                cifsInfo = CIFS_I(inode);
                cifsInfo->cifsAttrs = attr;
-               cFYI(1, ("Old time %ld ", cifsInfo->time));
+               cFYI(1, ("Old time %ld", cifsInfo->time));
                cifsInfo->time = jiffies;
-               cFYI(1, ("New time %ld ", cifsInfo->time));
+               cFYI(1, ("New time %ld", cifsInfo->time));
 
                /* blksize needs to be multiple of two. So safer to default to
                blksize and blkbits set in superblock so 2**blkbits and blksize
                will match rather than setting to:
                (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
 
-               /* Linux can not store file creation time unfortunately so we ignore it */
+               /* Linux can not store file creation time so ignore it */
                inode->i_atime =
                    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
                inode->i_mtime =
                    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
                inode->i_ctime =
                    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
-               cFYI(0, ("Attributes came in as 0x%x ", attr));
+               cFYI(0, ("Attributes came in as 0x%x", attr));
 
                /* set default mode. will override for dirs below */
                if (atomic_read(&cifsInfo->inUse) == 0)
@@ -519,10 +520,11 @@ int cifs_get_inode_info(struct inode **pinode,
                        else /* not direct, send byte range locks */
                                inode->i_fop = &cifs_file_ops;
 
-                       inode->i_data.a_ops = &cifs_addr_ops;
                        if(pTcon->ses->server->maxBuf < 
-                            4096 + MAX_CIFS_HDR_SIZE)
-                               inode->i_data.a_ops->readpages = NULL;
+                            PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
+                               inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+                       else
+                               inode->i_data.a_ops = &cifs_addr_ops;
                } else if (S_ISDIR(inode->i_mode)) {
                        cFYI(1, ("Directory inode"));
                        inode->i_op = &cifs_dir_inode_ops;
@@ -731,7 +733,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
        rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc) {
-               cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
+               cFYI(1, ("cifs_mkdir returned 0x%x", rc));
                d_drop(direntry);
        } else {
                inode->i_nlink++;
@@ -798,7 +800,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
        char *full_path = NULL;
        struct cifsInodeInfo *cifsInode;
 
-       cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode));
+       cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
 
        xid = GetXid();
 
@@ -1121,7 +1123,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 
        xid = GetXid();
 
-       cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x ",
+       cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
                 direntry->d_name.name, attrs->ia_valid));
 
        cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
@@ -1157,6 +1159,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                   when the local oplock break takes longer to flush
                   writebehind data than the SMB timeout for the SetPathInfo
                   request would allow */
+
                open_file = find_writable_file(cifsInode);
                if (open_file) {
                        __u16 nfid = open_file->netfid;
@@ -1289,7 +1292,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                it may be useful to Windows - but we do
                not want to set ctime unless some other
                timestamp is changing */
-               cFYI(1, ("CIFS - CTIME changed "));
+               cFYI(1, ("CIFS - CTIME changed"));
                time_buf.ChangeTime =
                    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
        } else
@@ -1356,7 +1359,7 @@ cifs_setattr_exit:
 
 void cifs_delete_inode(struct inode *inode)
 {
-       cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
+       cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
        /* may have to add back in if and when safe distributed caching of
           directories added e.g. via FindNotify */
 }
index 2ec99f8331422a2e089cc8f0b0b1381eddc6e131..a57f5d6e6213d6f23e693c88a98c3d539eb4ae6a 100644 (file)
@@ -167,7 +167,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
                return -ENOMEM;
        }
 
-       cFYI(1, ("Full path: %s ", full_path));
+       cFYI(1, ("Full path: %s", full_path));
        cFYI(1, ("symname is %s", symname));
 
        /* BB what if DFS and this volume is on different share? BB */
@@ -186,8 +186,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
                                                 inode->i_sb,xid);
 
                if (rc != 0) {
-                       cFYI(1,
-                            ("Create symlink worked but get_inode_info failed with rc = %d ",
+                       cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
                              rc));
                } else {
                        if (pTcon->nocase)
@@ -289,7 +288,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
                                        else {
                                                cFYI(1,("num referral: %d",num_referrals));
                                                if(referrals) {
-                                                       cFYI(1,("referral string: %s ",referrals));
+                                                       cFYI(1,("referral string: %s",referrals));
                                                        strncpy(tmpbuffer, referrals, len-1);                            
                                                }
                                        }
index fafd056426e4b1d9b3c7fea6c0d3fe2ea7c9340f..22c937e5884f36baf85e49cb9f3c3fc014de4522 100644 (file)
@@ -101,6 +101,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
        kfree(buf_to_free->serverDomain);
        kfree(buf_to_free->serverNOS);
        kfree(buf_to_free->password);
+       kfree(buf_to_free->domainName);
        kfree(buf_to_free);
 }
 
@@ -499,11 +500,12 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
                if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
                        data_offset = le32_to_cpu(pSMBr->DataOffset);
 
-                       pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol
-                               + data_offset);
-                       cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName,
+                       pnotify = (struct file_notify_information *)
+                               ((char *)&pSMBr->hdr.Protocol + data_offset);
+                       cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName,
                                pnotify->Action));  /* BB removeme BB */
-                    /*   cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */
+                    /*   cifs_dump_mem("Rcvd notify Data: ",buf,
+                               sizeof(struct smb_hdr)+60); */
                        return TRUE;
                }
                if(pSMBr->hdr.Status.CifsError) {
index 5de74d216fdd75533f23e89ef465823ea63d5ffc..b66eff5dc62445b1e4478811e26ddccaea2a0c85 100644 (file)
@@ -84,11 +84,11 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
 
 static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
        {ERRerror, -EIO},
-       {ERRbadpw, -EPERM},
+       {ERRbadpw, -EACCES},  /* was EPERM */
        {ERRbadtype, -EREMOTE},
        {ERRaccess, -EACCES},
        {ERRinvtid, -ENXIO},
-       {ERRinvnetname, -ENODEV},
+       {ERRinvnetname, -ENXIO},
        {ERRinvdevice, -ENXIO},
        {ERRqfull, -ENOSPC},
        {ERRqtoobig, -ENOSPC},
diff --git a/fs/cifs/ntlmssp.c b/fs/cifs/ntlmssp.c
deleted file mode 100644 (file)
index 115359c..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- *   fs/cifs/ntlmssp.h
- *
- *   Copyright (c) International Business Machines  Corp., 2006
- *   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 "cifspdu.h"
-#include "cifsglob.h"
-#include "cifsproto.h"
-#include "cifs_unicode.h"
-#include "cifs_debug.h"
-#include "ntlmssp.h"
-#include "nterr.h"
-
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
-{
-       __u32 capabilities = 0;
-
-       /* init fields common to all four types of SessSetup */
-       /* note that header is initialized to zero in header_assemble */
-       pSMB->req.AndXCommand = 0xFF;
-       pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
-       pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
-
-       /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
-
-       /* BB verify whether signing required on neg or just on auth frame 
-          (and NTLM case) */
-
-       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
-                       CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
-
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-               pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
-       if (ses->capabilities & CAP_UNICODE) {
-               pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
-               capabilities |= CAP_UNICODE;
-       }
-       if (ses->capabilities & CAP_STATUS32) {
-               pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
-               capabilities |= CAP_STATUS32;
-       }
-       if (ses->capabilities & CAP_DFS) {
-               pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
-               capabilities |= CAP_DFS;
-       }
-
-       /* BB check whether to init vcnum BB */
-       return capabilities;
-}
-int 
-CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int type,
-                 int * pNTLMv2_flg, const struct nls_table *nls_cp)
-{
-       int rc = 0;
-       int wct;
-       struct smb_hdr *smb_buffer;
-       char *bcc_ptr;
-       SESSION_SETUP_ANDX *pSMB;
-       __u32 capabilities;
-
-       if(ses == NULL)
-               return -EINVAL;
-
-       cFYI(1,("SStp type: %d",type));
-       if(type < CIFS_NTLM) {
-#ifndef CONFIG_CIFS_WEAK_PW_HASH
-               /* LANMAN and plaintext are less secure and off by default.
-               So we make this explicitly be turned on in kconfig (in the
-               build) and turned on at runtime (changed from the default)
-               in proc/fs/cifs or via mount parm.  Unfortunately this is
-               needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
-               return -EOPNOTSUPP;
-#endif
-               wct = 10; /* lanman 2 style sessionsetup */
-       } else if(type < CIFS_NTLMSSP_NEG)
-               wct = 13; /* old style NTLM sessionsetup */
-       else /* same size for negotiate or auth, NTLMSSP or extended security */
-               wct = 12;
-
-       rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
-                           (void **)&smb_buffer);
-       if(rc)
-               return rc;
-
-       pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
-
-       capabilities = cifs_ssetup_hdr(ses, pSMB);
-       bcc_ptr = pByteArea(smb_buffer);
-       if(type > CIFS_NTLM) {
-               pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
-               capabilities |= CAP_EXTENDED_SECURITY;
-               pSMB->req.Capabilities = cpu_to_le32(capabilities);
-               /* BB set password lengths */
-       } else if(type < CIFS_NTLM) /* lanman */ {
-               /* no capabilities flags in old lanman negotiation */
-               /* pSMB->old_req.PasswordLength = */ /* BB fixme BB */
-       } else /* type CIFS_NTLM */ {
-               pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
-               pSMB->req_no_secext.CaseInsensitivePasswordLength =
-                       cpu_to_le16(CIFS_SESSION_KEY_SIZE);
-               pSMB->req_no_secext.CaseSensitivePasswordLength =
-                       cpu_to_le16(CIFS_SESSION_KEY_SIZE);
-       }
-
-
-       /* copy session key */
-
-       /* if Unicode, align strings to two byte boundary */
-
-       /* copy user name */ /* BB Do we need to special case null user name? */
-
-       /* copy domain name */
-
-       /* copy Linux version */
-
-       /* copy network operating system name */
-
-       /* update bcc and smb buffer length */
-
-/*     rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */
-       /* SMB request buf freed in SendReceive2 */
-
-       return rc;
-}
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
index b689c5035124d137d1b019393cbad2d0b1123bf9..03bbcb3779136b1546da05e4d5de0367b0d43d23 100644 (file)
@@ -21,6 +21,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <linux/fs.h>
+#include <linux/pagemap.h>
 #include <linux/stat.h>
 #include <linux/smp_lock.h>
 #include "cifspdu.h"
@@ -31,8 +32,8 @@
 #include "cifs_fs_sb.h"
 #include "cifsfs.h"
 
-/* BB fixme - add debug wrappers around this function to disable it fixme BB */
-/* static void dump_cifs_file_struct(struct file *file, char *label)
+#ifdef CONFIG_CIFS_DEBUG2
+static void dump_cifs_file_struct(struct file *file, char *label)
 {
        struct cifsFileInfo * cf;
 
@@ -53,7 +54,8 @@
                }
                
        }
-} */
+}
+#endif /* DEBUG2 */
 
 /* Returns one if new inode created (which therefore needs to be hashed) */
 /* Might check in the future if inode number changed so we can rehash inode */
@@ -107,32 +109,52 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
        return rc;
 }
 
-static void fill_in_inode(struct inode *tmp_inode,
-       FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode)
+static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
+               char * buf, int *pobject_type, int isNewInode)
 {
        loff_t local_size;
        struct timespec local_mtime;
 
        struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
-       __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
-       __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize);
-       __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
-
-       cifsInfo->cifsAttrs = attr;
-       cifsInfo->time = jiffies;
+       __u32 attr;
+       __u64 allocation_size;
+       __u64 end_of_file;
 
        /* save mtime and size */
        local_mtime = tmp_inode->i_mtime;
        local_size  = tmp_inode->i_size;
 
+       if(new_buf_type) {
+               FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
+
+               attr = le32_to_cpu(pfindData->ExtFileAttributes);
+               allocation_size = le64_to_cpu(pfindData->AllocationSize);
+               end_of_file = le64_to_cpu(pfindData->EndOfFile);
+               tmp_inode->i_atime =
+                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+               tmp_inode->i_mtime =
+                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
+               tmp_inode->i_ctime =
+                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+       } else { /* legacy, OS2 and DOS style */
+               FIND_FILE_STANDARD_INFO * pfindData = 
+                       (FIND_FILE_STANDARD_INFO *)buf;
+
+               attr = le16_to_cpu(pfindData->Attributes);
+               allocation_size = le32_to_cpu(pfindData->AllocationSize);
+               end_of_file = le32_to_cpu(pfindData->DataSize);
+               tmp_inode->i_atime = CURRENT_TIME;
+               /* tmp_inode->i_mtime =  BB FIXME - add dos time handling
+               tmp_inode->i_ctime = 0;   BB FIXME */
+
+       }
+
        /* Linux can not store file creation time unfortunately so ignore it */
-       tmp_inode->i_atime =
-           cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
-       tmp_inode->i_mtime =
-           cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
-       tmp_inode->i_ctime =
-           cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+
+       cifsInfo->cifsAttrs = attr;
+       cifsInfo->time = jiffies;
+
        /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
        /* 2767 perms - indicate mandatory locking */
                /* BB fill in uid and gid here? with help from winbind? 
@@ -215,11 +237,13 @@ static void fill_in_inode(struct inode *tmp_inode,
                else
                        tmp_inode->i_fop = &cifs_file_ops;
 
-               tmp_inode->i_data.a_ops = &cifs_addr_ops;
                if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
                   (cifs_sb->tcon->ses->server->maxBuf <
-                       4096 + MAX_CIFS_HDR_SIZE))
-                       tmp_inode->i_data.a_ops->readpages = NULL;
+                       PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+                       tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+               else
+                       tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
                if(isNewInode)
                        return; /* No sense invalidating pages for new inode
                                   since have not started caching readahead file
@@ -338,11 +362,12 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
                else
                        tmp_inode->i_fop = &cifs_file_ops;
 
-               tmp_inode->i_data.a_ops = &cifs_addr_ops;
                if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
                   (cifs_sb->tcon->ses->server->maxBuf < 
-                       4096 + MAX_CIFS_HDR_SIZE))
-                       tmp_inode->i_data.a_ops->readpages = NULL;
+                       PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+                       tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+               else
+                       tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
                if(isNewInode)
                        return; /* No sense invalidating pages for new inode since we
@@ -415,7 +440,10 @@ static int initiate_cifs_search(const int xid, struct file *file)
 ffirst_retry:
        /* test for Unix extensions */
        if (pTcon->ses->capabilities & CAP_UNIX) {
-               cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; 
+               cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
+       } else if ((pTcon->ses->capabilities & 
+                       (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
+               cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
        } 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? */ {
@@ -451,12 +479,19 @@ static int cifs_unicode_bytelen(char *str)
        return len << 1;
 }
 
-static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
+static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
 {
        char * new_entry;
        FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
 
-       new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
+       if(level == SMB_FIND_FILE_INFO_STANDARD) {
+               FIND_FILE_STANDARD_INFO * pfData;
+               pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
+
+               new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
+                               pfData->FileNameLength;
+       } else
+               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) {
@@ -464,7 +499,10 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
                      ("search entry %p began after end of SMB %p old entry %p",
                        new_entry, end_of_smb, old_entry)); 
                return NULL;
-       } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) {
+       } else if(((level == SMB_FIND_FILE_INFO_STANDARD) &&
+                  (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) ||
+                 ((level != SMB_FIND_FILE_INFO_STANDARD) &&
+                  (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
                cERROR(1,("search entry %p extends after end of SMB %p",
                        new_entry, end_of_smb));
                return NULL;
@@ -482,7 +520,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
        char * filename = NULL;
        int len = 0; 
 
-       if(cfile->srch_inf.info_level == 0x202) {
+       if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
                FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                if(cfile->srch_inf.unicode) {
@@ -491,26 +529,34 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
                        /* BB should we make this strnlen of PATH_MAX? */
                        len = strnlen(filename, 5);
                }
-       } else if(cfile->srch_inf.info_level == 0x101) {
+       } else if(cfile->srch_inf.info_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(cfile->srch_inf.info_level == 0x102) {
+       } else if(cfile->srch_inf.info_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(cfile->srch_inf.info_level == 0x105) {
+       } else if(cfile->srch_inf.info_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);
-       } else if(cfile->srch_inf.info_level == 0x104) {
+       } else if(cfile->srch_inf.info_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 if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
+               FIND_FILE_STANDARD_INFO * pFindData =
+                       (FIND_FILE_STANDARD_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));
        }
@@ -597,7 +643,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
        . and .. for the root of a drive and for those we need
        to start two entries earlier */
 
-/*     dump_cifs_file_struct(file, "In fce ");*/
+#ifdef CONFIG_CIFS_DEBUG2
+       dump_cifs_file_struct(file, "In fce ");
+#endif
        if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
             is_dir_changed(file)) || 
           (index_to_find < first_entry_in_buffer)) {
@@ -644,10 +692,12 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
                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)); 
+               cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
+
                for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
                        /* go entry by entry figuring out which is first */
-                       current_entry = nxt_dir_entry(current_entry,end_of_smb);
+                       current_entry = nxt_dir_entry(current_entry,end_of_smb,
+                                               cifsFile->srch_inf.info_level);
                }
                if((current_entry == NULL) && (i < pos_in_buf)) {
                        /* BB fixme - check if we should flag this error */
@@ -674,7 +724,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 /* 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 cifs_sb_info * cifs_sb, ino_t *pinum)
+       struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum)
 {
        int rc = 0;
        unsigned int len = 0;
@@ -718,10 +768,22 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
                        (FILE_BOTH_DIRECTORY_INFO *)current_entry;
                filename = &pFindData->FileName[0];
                len = le32_to_cpu(pFindData->FileNameLength);
+       } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
+               FIND_FILE_STANDARD_INFO * pFindData =
+                       (FIND_FILE_STANDARD_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               /* one byte length, no name conversion */
+               len = (unsigned int)pFindData->FileNameLength;
        } else {
                cFYI(1,("Unknown findfirst level %d",level));
                return -EINVAL;
        }
+
+       if(len > max_len) {
+               cERROR(1,("bad search response length %d past smb end", len));
+               return -EINVAL;
+       }
+
        if(unicode) {
                /* BB fixme - test with long names */
                /* Note converted filename can be longer than in unicode */
@@ -741,7 +803,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
 }
 
 static int cifs_filldir(char *pfindEntry, struct file *file,
-       filldir_t filldir, void *direntry, char *scratch_buf)
+       filldir_t filldir, void *direntry, char *scratch_buf, int max_len)
 {
        int rc = 0;
        struct qstr qstring;
@@ -777,6 +839,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
        rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
                        pCifsF->srch_inf.info_level,
                        pCifsF->srch_inf.unicode,cifs_sb,
+                       max_len,
                        &inum /* returned */);
 
        if(rc)
@@ -798,13 +861,16 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
        /* we pass in rc below, indicating whether it is a new inode,
           so we can figure out whether to invalidate the inode cached
           data if the file has changed */
-       if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
+       if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
                unix_fill_in_inode(tmp_inode,
-                                  (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc);
-       } else {
-               fill_in_inode(tmp_inode,
-                             (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
-       }
+                                  (FILE_UNIX_INFO *)pfindEntry,
+                                  &obj_type, rc);
+       else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
+               fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
+                               pfindEntry, &obj_type, rc);
+       else
+               fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
+       
        
        rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
                     tmp_inode->i_ino,obj_type);
@@ -864,6 +930,12 @@ static int cifs_save_resume_key(const char *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_INFO_STANDARD) {
+               FIND_FILE_STANDARD_INFO * pFindData =
+                       (FIND_FILE_STANDARD_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               /* one byte length, no name conversion */
+               len = (unsigned int)pFindData->FileNameLength;
        } else {
                cFYI(1,("Unknown findfirst level %d",level));
                return -EINVAL;
@@ -884,6 +956,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
        int num_to_fill = 0;
        char * tmp_buf = NULL;
        char * end_of_smb;
+       int max_len;
 
        xid = GetXid();
 
@@ -909,7 +982,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
        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 "));
+                       cERROR(1, ("Filldir for parent dir failed"));
                        rc = -ENOMEM;
                        break;
                }
@@ -959,10 +1032,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                        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);
+                       num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
+               max_len = smbCalcSize((struct smb_hdr *)
+                               cifsFile->srch_inf.ntwrk_buf_start);
+               end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
+
                /* To be safe - for UCS to UTF-8 with strings loaded
                with the rare long characters alloc more to account for
                such multibyte target UTF-8 characters. cifs_unicode.c,
@@ -977,17 +1051,19 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                        }
                        /* if buggy server returns . and .. late do
                        we want to check for that here? */
-                       rc = cifs_filldir(current_entry, file, 
-                                       filldir, direntry,tmp_buf);
+                       rc = cifs_filldir(current_entry, file,
+                                       filldir, direntry, tmp_buf, max_len);
                        file->f_pos++;
-                       if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) {
+                       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 */
+                                       file->f_pos,tmp_buf));
                                cifs_save_resume_key(current_entry,cifsFile);
                                break;
                        } else 
-                               current_entry = nxt_dir_entry(current_entry,
-                                                             end_of_smb);
+                               current_entry = 
+                                       nxt_dir_entry(current_entry, end_of_smb,
+                                               cifsFile->srch_inf.info_level);
                }
                kfree(tmp_buf);
                break;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
new file mode 100644 (file)
index 0000000..7202d53
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ *   fs/cifs/sess.c
+ *
+ *   SMB/CIFS session setup handling routines
+ *
+ *   Copyright (c) International Business Machines  Corp., 2006
+ *   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 "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "ntlmssp.h"
+#include "nterr.h"
+#include <linux/utsname.h>
+
+extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
+                         unsigned char *p24);
+
+static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
+{
+       __u32 capabilities = 0;
+
+       /* init fields common to all four types of SessSetup */
+       /* note that header is initialized to zero in header_assemble */
+       pSMB->req.AndXCommand = 0xFF;
+       pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+       pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+
+       /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
+
+       /* BB verify whether signing required on neg or just on auth frame 
+          (and NTLM case) */
+
+       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+                       CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
+
+       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+               pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+       if (ses->capabilities & CAP_UNICODE) {
+               pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
+               capabilities |= CAP_UNICODE;
+       }
+       if (ses->capabilities & CAP_STATUS32) {
+               pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
+               capabilities |= CAP_STATUS32;
+       }
+       if (ses->capabilities & CAP_DFS) {
+               pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
+               capabilities |= CAP_DFS;
+       }
+       if (ses->capabilities & CAP_UNIX) {
+               capabilities |= CAP_UNIX;
+       }
+
+       /* BB check whether to init vcnum BB */
+       return capabilities;
+}
+
+static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
+                           const struct nls_table * nls_cp)
+{
+       char * bcc_ptr = *pbcc_area;
+       int bytes_ret = 0;
+
+       /* BB FIXME add check that strings total less
+       than 335 or will need to send them as arrays */
+
+       /* unicode strings, must be word aligned before the call */
+/*     if ((long) bcc_ptr % 2) {
+               *bcc_ptr = 0;
+               bcc_ptr++;
+       } */
+       /* copy user */
+       if(ses->userName == NULL) {
+               /* BB what about null user mounts - check that we do this BB */
+       } else { /* 300 should be long enough for any conceivable user name */
+               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName,
+                                         300, nls_cp);
+       }
+       bcc_ptr += 2 * bytes_ret;
+       bcc_ptr += 2; /* account for null termination */
+       /* copy domain */
+       if(ses->domainName == NULL)
+               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr,
+                                         "CIFS_LINUX_DOM", 32, nls_cp);
+       else
+               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, 
+                                         256, nls_cp);
+       bcc_ptr += 2 * bytes_ret;
+       bcc_ptr += 2;  /* account for null terminator */
+
+       /* Copy OS version */
+       bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
+                                 nls_cp);
+       bcc_ptr += 2 * bytes_ret;
+       bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
+                                 32, nls_cp);
+       bcc_ptr += 2 * bytes_ret;
+       bcc_ptr += 2; /* trailing null */
+
+       bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
+                                  32, nls_cp);
+       bcc_ptr += 2 * bytes_ret;
+       bcc_ptr += 2; /* trailing null */
+
+       *pbcc_area = bcc_ptr;
+}
+
+static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
+                         const struct nls_table * nls_cp)
+{
+       char * bcc_ptr = *pbcc_area;
+
+       /* copy user */
+       /* BB what about null user mounts - check that we do this BB */
+        /* copy user */
+        if(ses->userName == NULL) {
+                /* BB what about null user mounts - check that we do this BB */
+        } else { /* 300 should be long enough for any conceivable user name */
+                strncpy(bcc_ptr, ses->userName, 300);
+        }
+       /* BB improve check for overflow */
+        bcc_ptr += strnlen(ses->userName, 300);
+       *bcc_ptr = 0;
+        bcc_ptr++; /* account for null termination */
+
+        /* copy domain */
+       
+        if(ses->domainName == NULL) {
+                strcpy(bcc_ptr, "CIFS_LINUX_DOM");
+               bcc_ptr += 14;  /* strlen(CIFS_LINUX_DOM) */
+       } else {
+                strncpy(bcc_ptr, ses->domainName, 256); 
+               bcc_ptr += strnlen(ses->domainName, 256);
+       }
+       *bcc_ptr = 0;
+       bcc_ptr++;
+
+       /* BB check for overflow here */
+
+       strcpy(bcc_ptr, "Linux version ");
+       bcc_ptr += strlen("Linux version ");
+       strcpy(bcc_ptr, system_utsname.release);
+       bcc_ptr += strlen(system_utsname.release) + 1;
+
+       strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+       bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+
+        *pbcc_area = bcc_ptr;
+}
+
+static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
+                            const struct nls_table * nls_cp)
+{
+       int rc = 0;
+       int words_left, len;
+       char * data = *pbcc_area;
+
+
+
+       cFYI(1,("bleft %d",bleft));
+
+
+       /* word align, if bytes remaining is not even */
+       if(bleft % 2) {
+               bleft--;
+               data++;
+       }
+       words_left = bleft / 2;
+
+       /* save off server operating system */
+       len = UniStrnlen((wchar_t *) data, words_left);
+
+/* We look for obvious messed up bcc or strings in response so we do not go off
+   the end since (at least) WIN2K and Windows XP have a major bug in not null
+   terminating last Unicode string in response  */
+       if(len >= words_left)
+               return rc;
+
+       if(ses->serverOS)
+               kfree(ses->serverOS);
+       /* UTF-8 string will not grow more than four times as big as UCS-16 */
+       ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
+       if(ses->serverOS != NULL) {
+               cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len,
+                                  nls_cp);
+       }
+       data += 2 * (len + 1);
+       words_left -= len + 1;
+
+       /* save off server network operating system */
+       len = UniStrnlen((wchar_t *) data, words_left);
+
+       if(len >= words_left)
+               return rc;
+
+       if(ses->serverNOS)
+               kfree(ses->serverNOS);
+       ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
+       if(ses->serverNOS != NULL) {
+               cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
+                                  nls_cp);
+               if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) {
+                       cFYI(1,("NT4 server"));
+                       ses->flags |= CIFS_SES_NT4;
+               }
+       }
+       data += 2 * (len + 1);
+       words_left -= len + 1;
+
+        /* save off server domain */
+        len = UniStrnlen((wchar_t *) data, words_left);
+
+        if(len > words_left)
+                return rc;
+
+        if(ses->serverDomain)
+                kfree(ses->serverDomain);
+        ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
+        if(ses->serverDomain != NULL) {
+                cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
+                                   nls_cp);
+                ses->serverDomain[2*len] = 0;
+                ses->serverDomain[(2*len) + 1] = 0;
+        }
+        data += 2 * (len + 1);
+        words_left -= len + 1;
+       
+       cFYI(1,("words left: %d",words_left));
+
+       return rc;
+}
+
+static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
+                            const struct nls_table * nls_cp)
+{
+       int rc = 0;
+       int len;
+       char * bcc_ptr = *pbcc_area;
+
+       cFYI(1,("decode sessetup ascii. bleft %d", bleft));
+       
+       len = strnlen(bcc_ptr, bleft);
+       if(len >= bleft)
+               return rc;
+       
+       if(ses->serverOS)
+               kfree(ses->serverOS);
+
+       ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
+       if(ses->serverOS)
+               strncpy(ses->serverOS, bcc_ptr, len);
+
+       bcc_ptr += len + 1;
+       bleft -= len + 1;
+
+       len = strnlen(bcc_ptr, bleft);
+       if(len >= bleft)
+               return rc;
+
+       if(ses->serverNOS)
+               kfree(ses->serverNOS);
+
+       ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
+       if(ses->serverNOS)
+               strncpy(ses->serverNOS, bcc_ptr, len);
+
+       bcc_ptr += len + 1;
+       bleft -= len + 1;
+
+        len = strnlen(bcc_ptr, bleft);
+        if(len > bleft)
+                return rc;
+
+        if(ses->serverDomain)
+                kfree(ses->serverDomain);
+
+        ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
+        if(ses->serverOS)
+                strncpy(ses->serverOS, bcc_ptr, len);
+
+        bcc_ptr += len + 1;
+       bleft -= len + 1;
+
+       cFYI(1,("ascii: bytes left %d",bleft));
+
+       return rc;
+}
+
+int 
+CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
+               const struct nls_table *nls_cp)
+{
+       int rc = 0;
+       int wct;
+       struct smb_hdr *smb_buf;
+       char *bcc_ptr;
+       char *str_area;
+       SESSION_SETUP_ANDX *pSMB;
+       __u32 capabilities;
+       int count;
+       int resp_buf_type = 0;
+       struct kvec iov[2];
+       enum securityEnum type;
+       __u16 action;
+       int bytes_remaining;
+
+       if(ses == NULL)
+               return -EINVAL;
+
+       type = ses->server->secType;
+
+       cFYI(1,("sess setup type %d",type));
+       if(type == LANMAN) {
+#ifndef CONFIG_CIFS_WEAK_PW_HASH
+               /* LANMAN and plaintext are less secure and off by default.
+               So we make this explicitly be turned on in kconfig (in the
+               build) and turned on at runtime (changed from the default)
+               in proc/fs/cifs or via mount parm.  Unfortunately this is
+               needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
+               return -EOPNOTSUPP;
+#endif
+               wct = 10; /* lanman 2 style sessionsetup */
+       } else if((type == NTLM) || (type == NTLMv2)) { 
+               /* For NTLMv2 failures eventually may need to retry NTLM */
+               wct = 13; /* old style NTLM sessionsetup */
+       } else /* same size for negotiate or auth, NTLMSSP or extended security */
+               wct = 12;
+
+       rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
+                           (void **)&smb_buf);
+       if(rc)
+               return rc;
+
+       pSMB = (SESSION_SETUP_ANDX *)smb_buf;
+
+       capabilities = cifs_ssetup_hdr(ses, pSMB);
+
+       /* we will send the SMB in two pieces,
+       a fixed length beginning part, and a
+       second part which will include the strings
+       and rest of bcc area, in order to avoid having
+       to do a large buffer 17K allocation */
+        iov[0].iov_base = (char *)pSMB;
+        iov[0].iov_len = smb_buf->smb_buf_length + 4;
+
+       /* 2000 big enough to fit max user, domain, NOS name etc. */
+       str_area = kmalloc(2000, GFP_KERNEL);
+       bcc_ptr = str_area;
+
+       if(type == LANMAN) {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+               char lnm_session_key[CIFS_SESS_KEY_SIZE];
+
+               /* no capabilities flags in old lanman negotiation */
+
+               pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE; 
+               /* BB calculate hash with password */
+               /* and copy into bcc */
+
+               calc_lanman_hash(ses, lnm_session_key);
+
+/* #ifdef CONFIG_CIFS_DEBUG2
+               cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
+                       CIFS_SESS_KEY_SIZE);
+#endif */
+               memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+
+               /* can not sign if LANMAN negotiated so no need
+               to calculate signing key? but what if server
+               changed to do higher than lanman dialect and
+               we reconnected would we ever calc signing_key? */
+
+               cFYI(1,("Negotiating LANMAN setting up strings"));
+               /* Unicode not allowed for LANMAN dialects */
+               ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+#endif    
+       } else if (type == NTLM) {
+               char ntlm_session_key[CIFS_SESS_KEY_SIZE];
+
+               pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+               pSMB->req_no_secext.CaseInsensitivePasswordLength =
+                       cpu_to_le16(CIFS_SESS_KEY_SIZE);
+               pSMB->req_no_secext.CaseSensitivePasswordLength =
+                       cpu_to_le16(CIFS_SESS_KEY_SIZE);
+       
+               /* calculate session key */
+               SMBNTencrypt(ses->password, ses->server->cryptKey,
+                            ntlm_session_key);
+
+               if(first_time) /* should this be moved into common code 
+                                 with similar ntlmv2 path? */
+                       cifs_calculate_mac_key(ses->server->mac_signing_key,
+                               ntlm_session_key, ses->password);
+               /* copy session key */
+
+               memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               if(ses->capabilities & CAP_UNICODE) {
+                       /* unicode strings must be word aligned */
+                       if (iov[0].iov_len % 2) {
+                               *bcc_ptr = 0;
+                               bcc_ptr++;              
+                       }       
+                       unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
+               } else
+                       ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+       } else if (type == NTLMv2) {
+               char * v2_sess_key = 
+                       kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL);
+
+               /* BB FIXME change all users of v2_sess_key to
+                  struct ntlmv2_resp */
+
+               if(v2_sess_key == NULL) {
+                       cifs_small_buf_release(smb_buf);
+                       return -ENOMEM;
+               }
+
+               pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+
+               /* LM2 password would be here if we supported it */
+               pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
+               /*      cpu_to_le16(LM2_SESS_KEY_SIZE); */
+
+               pSMB->req_no_secext.CaseSensitivePasswordLength =
+                       cpu_to_le16(sizeof(struct ntlmv2_resp));
+
+               /* calculate session key */
+               setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
+               if(first_time) /* should this be moved into common code
+                                 with similar ntlmv2 path? */
+               /*   cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
+                               response BB FIXME, v2_sess_key); */
+
+               /* copy session key */
+
+       /*      memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
+               bcc_ptr += LM2_SESS_KEY_SIZE; */
+               memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp));
+               bcc_ptr += sizeof(struct ntlmv2_resp);
+               kfree(v2_sess_key);
+               if(ses->capabilities & CAP_UNICODE) {
+                       if(iov[0].iov_len % 2) {
+                               *bcc_ptr = 0;
+                       }       bcc_ptr++;
+                       unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
+               } else
+                       ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+       } else /* NTLMSSP or SPNEGO */ {
+               pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+               capabilities |= CAP_EXTENDED_SECURITY;
+               pSMB->req.Capabilities = cpu_to_le32(capabilities);
+               /* BB set password lengths */
+       }
+
+       count = (long) bcc_ptr - (long) str_area;
+       smb_buf->smb_buf_length += count;
+
+       BCC_LE(smb_buf) = cpu_to_le16(count);
+
+       iov[1].iov_base = str_area;
+       iov[1].iov_len = count; 
+       rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0);
+       /* SMB request buf freed in SendReceive2 */
+
+       cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
+       if(rc)
+               goto ssetup_exit;
+
+       pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
+       smb_buf = (struct smb_hdr *)iov[0].iov_base;
+
+       if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
+               rc = -EIO;
+               cERROR(1,("bad word count %d", smb_buf->WordCount));
+               goto ssetup_exit;
+       }
+       action = le16_to_cpu(pSMB->resp.Action);
+       if (action & GUEST_LOGIN)
+               cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */
+       ses->Suid = smb_buf->Uid;   /* UID left in wire format (le) */
+       cFYI(1, ("UID = %d ", ses->Suid));
+       /* response can have either 3 or 4 word count - Samba sends 3 */
+       /* and lanman response is 3 */
+       bytes_remaining = BCC(smb_buf);
+       bcc_ptr = pByteArea(smb_buf);
+
+       if(smb_buf->WordCount == 4) {
+               __u16 blob_len;
+               blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
+               bcc_ptr += blob_len;
+               if(blob_len > bytes_remaining) {
+                       cERROR(1,("bad security blob length %d", blob_len));
+                       rc = -EINVAL;
+                       goto ssetup_exit;
+               }
+               bytes_remaining -= blob_len;
+       }       
+
+       /* BB check if Unicode and decode strings */
+       if(smb_buf->Flags2 & SMBFLG2_UNICODE)
+               rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
+                                                  ses, nls_cp);
+       else
+               rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
+       
+ssetup_exit:
+       kfree(str_area);
+       if(resp_buf_type == CIFS_SMALL_BUFFER) {
+               cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
+               cifs_small_buf_release(iov[0].iov_base);
+       } else if(resp_buf_type == CIFS_LARGE_BUFFER)
+               cifs_buf_release(iov[0].iov_base);
+
+       return rc;
+}
index 6103bcdfb16d9e425525bf20ec87fabb2da5ec2d..f518c5e45035c50955b51c55d08ab86b66127842 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/random.h>
 #include "cifs_unicode.h"
 #include "cifspdu.h"
+#include "cifsglob.h"
 #include "md5.h"
 #include "cifs_debug.h"
 #include "cifsencrypt.h"
index 3da80409466cff7e30dc428cdfb0321828a8a094..17ba329e2b3de5cbf02b973cf0b3a04515736b43 100644 (file)
@@ -654,8 +654,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 
        if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
                up(&ses->server->tcpSem);
-               cERROR(1,
-                      ("Illegal length, greater than maximum frame, %d ",
+               cERROR(1, ("Illegal length, greater than maximum frame, %d",
                        in_buf->smb_buf_length));
                DeleteMidQEntry(midQ);
                /* If not lock req, update # of requests on wire to server */
index 7caee8d8ea3b9a24656f40a20c247986f796d39f..803aacf0d49c29576252dcbe2aa2ff8e73d9e5f5 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/proc_fs.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <linux/file.h>
@@ -365,22 +364,12 @@ static int init_coda_psdev(void)
                err = PTR_ERR(coda_psdev_class);
                goto out_chrdev;
        }               
-       devfs_mk_dir ("coda");
-       for (i = 0; i < MAX_CODADEVS; i++) {
+       for (i = 0; i < MAX_CODADEVS; i++)
                class_device_create(coda_psdev_class, NULL,
                                MKDEV(CODA_PSDEV_MAJOR,i), NULL, "cfs%d", i);
-               err = devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i),
-                               S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i);
-               if (err)
-                       goto out_class;
-       }
        coda_sysctl_init();
        goto out;
 
-out_class:
-       for (i = 0; i < MAX_CODADEVS; i++) 
-               class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
-       class_destroy(coda_psdev_class);
 out_chrdev:
        unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
 out:
@@ -419,12 +408,9 @@ static int __init init_coda(void)
        }
        return 0;
 out:
-       for (i = 0; i < MAX_CODADEVS; i++) {
+       for (i = 0; i < MAX_CODADEVS; i++)
                class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
-               devfs_remove("coda/%d", i);
-       }
        class_destroy(coda_psdev_class);
-       devfs_remove("coda");
        unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
        coda_sysctl_clean();
 out1:
@@ -441,12 +427,9 @@ static void __exit exit_coda(void)
         if ( err != 0 ) {
                 printk("coda: failed to unregister filesystem\n");
         }
-       for (i = 0; i < MAX_CODADEVS; i++) {
+       for (i = 0; i < MAX_CODADEVS; i++)
                class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
-               devfs_remove("coda/%d", i);
-       }
        class_destroy(coda_psdev_class);
-       devfs_remove("coda");
        unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
        coda_sysctl_clean();
        coda_destroy_inodecache();
index b35e5bbd9c99b54047e843297d8c1e36b07bfb1e..76e00a65a75be512d0838d8d3b21e19873b1a6d1 100644 (file)
@@ -50,6 +50,6 @@ fail:
        return error;
 }
 
-struct address_space_operations coda_symlink_aops = {
+const struct address_space_operations coda_symlink_aops = {
        .readpage       = coda_symlink_filler,
 };
index d8ecfedef18940ba28c0cd042d71ce6e2fe3515f..d8d50a70c58d65064931f6b0b5a8f2fa1beaf1a0 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/loop.h>
 #include <linux/auto_fs.h>
 #include <linux/auto_fs4.h>
-#include <linux/devfs_fs.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
 #include <linux/fb.h>
index c153bd9534cb6d72066094c8110ce0f35fec3ff3..e14488ca6411fef8db1fb86e1252f49b99f9b2a7 100644 (file)
@@ -38,7 +38,7 @@
 
 extern struct super_block * configfs_sb;
 
-static struct address_space_operations configfs_aops = {
+static const struct address_space_operations configfs_aops = {
        .readpage       = simple_readpage,
        .prepare_write  = simple_prepare_write,
        .commit_write   = simple_commit_write
index c45d738608039c5a20a4b2055bc3dd8e4c40cfcf..223c0431042deaa8fb77aa99626100338e546f4e 100644 (file)
@@ -30,7 +30,7 @@
 static struct super_operations cramfs_ops;
 static struct inode_operations cramfs_dir_inode_operations;
 static const struct file_operations cramfs_directory_operations;
-static struct address_space_operations cramfs_aops;
+static const struct address_space_operations cramfs_aops;
 
 static DEFINE_MUTEX(read_mutex);
 
@@ -501,7 +501,7 @@ static int cramfs_readpage(struct file *file, struct page * page)
        return 0;
 }
 
-static struct address_space_operations cramfs_aops = {
+static const struct address_space_operations cramfs_aops = {
        .readpage = cramfs_readpage
 };
 
diff --git a/fs/devfs/Makefile b/fs/devfs/Makefile
deleted file mode 100644 (file)
index 6dd8d12..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the linux devfs-filesystem routines.
-#
-
-obj-$(CONFIG_DEVFS_FS) += devfs.o
-
-devfs-objs := base.o util.o
-
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
deleted file mode 100644 (file)
index 51a97f1..0000000
+++ /dev/null
@@ -1,2836 +0,0 @@
-/*  devfs (Device FileSystem) driver.
-
-    Copyright (C) 1998-2002  Richard Gooch
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 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
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
-    The postal address is:
-      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
-
-    ChangeLog
-
-    19980110   Richard Gooch <rgooch@atnf.csiro.au>
-               Original version.
-  v0.1
-    19980111   Richard Gooch <rgooch@atnf.csiro.au>
-               Created per-fs inode table rather than using inode->u.generic_ip
-  v0.2
-    19980111   Richard Gooch <rgooch@atnf.csiro.au>
-               Created .epoch inode which has a ctime of 0.
-              Fixed loss of named pipes when dentries lost.
-              Fixed loss of inode data when devfs_register() follows mknod().
-  v0.3
-    19980111   Richard Gooch <rgooch@atnf.csiro.au>
-               Fix for when compiling with CONFIG_KERNELD.
-    19980112   Richard Gooch <rgooch@atnf.csiro.au>
-               Fix for readdir() which sometimes didn't show entries.
-              Added <<tolerant>> option to <devfs_register>.
-  v0.4
-    19980113   Richard Gooch <rgooch@atnf.csiro.au>
-               Created <devfs_fill_file> function.
-  v0.5
-    19980115   Richard Gooch <rgooch@atnf.csiro.au>
-               Added subdirectory support. Major restructuring.
-    19980116   Richard Gooch <rgooch@atnf.csiro.au>
-               Fixed <find_by_dev> to not search major=0,minor=0.
-              Added symlink support.
-  v0.6
-    19980120   Richard Gooch <rgooch@atnf.csiro.au>
-               Created <devfs_mk_dir> function and support directory unregister
-    19980120   Richard Gooch <rgooch@atnf.csiro.au>
-               Auto-ownership uses real uid/gid rather than effective uid/gid.
-  v0.7
-    19980121   Richard Gooch <rgooch@atnf.csiro.au>
-               Supported creation of sockets.
-  v0.8
-    19980122   Richard Gooch <rgooch@atnf.csiro.au>
-               Added DEVFS_FL_HIDE_UNREG flag.
-              Interface change to <devfs_mk_symlink>.
-               Created <devfs_symlink> to support symlink(2).
-  v0.9
-    19980123   Richard Gooch <rgooch@atnf.csiro.au>
-               Added check to <devfs_fill_file> to check inode is in devfs.
-              Added optional traversal of symlinks.
-  v0.10
-    19980124   Richard Gooch <rgooch@atnf.csiro.au>
-               Created <devfs_get_flags> and <devfs_set_flags>.
-  v0.11
-    19980125   C. Scott Ananian <cananian@alumni.princeton.edu>
-               Created <devfs_find_handle>.
-    19980125   Richard Gooch <rgooch@atnf.csiro.au>
-               Allow removal of symlinks.
-  v0.12
-    19980125   Richard Gooch <rgooch@atnf.csiro.au>
-               Created <devfs_set_symlink_destination>.
-    19980126   Richard Gooch <rgooch@atnf.csiro.au>
-               Moved DEVFS_SUPER_MAGIC into header file.
-              Added DEVFS_FL_HIDE flag.
-              Created <devfs_get_maj_min>.
-              Created <devfs_get_handle_from_inode>.
-              Fixed minor bug in <find_by_dev>.
-    19980127   Richard Gooch <rgooch@atnf.csiro.au>
-              Changed interface to <find_by_dev>, <find_entry>,
-              <devfs_unregister>, <devfs_fill_file> and <devfs_find_handle>.
-              Fixed inode times when symlink created with symlink(2).
-  v0.13
-    19980129   C. Scott Ananian <cananian@alumni.princeton.edu>
-               Exported <devfs_set_symlink_destination>, <devfs_get_maj_min>
-              and <devfs_get_handle_from_inode>.
-    19980129   Richard Gooch <rgooch@atnf.csiro.au>
-              Created <devfs_unlink> to support unlink(2).
-  v0.14
-    19980129   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed kerneld support for entries in devfs subdirectories.
-    19980130   Richard Gooch <rgooch@atnf.csiro.au>
-              Bugfixes in <call_kerneld>.
-  v0.15
-    19980207   Richard Gooch <rgooch@atnf.csiro.au>
-              Call kerneld when looking up unregistered entries.
-  v0.16
-    19980326   Richard Gooch <rgooch@atnf.csiro.au>
-              Modified interface to <devfs_find_handle> for symlink traversal.
-  v0.17
-    19980331   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed persistence bug with device numbers for manually created
-              device files.
-              Fixed problem with recreating symlinks with different content.
-  v0.18
-    19980401   Richard Gooch <rgooch@atnf.csiro.au>
-              Changed to CONFIG_KMOD.
-              Hide entries which are manually unlinked.
-              Always invalidate devfs dentry cache when registering entries.
-              Created <devfs_rmdir> to support rmdir(2).
-              Ensure directories created by <devfs_mk_dir> are visible.
-  v0.19
-    19980402   Richard Gooch <rgooch@atnf.csiro.au>
-              Invalidate devfs dentry cache when making directories.
-              Invalidate devfs dentry cache when removing entries.
-              Fixed persistence bug with fifos.
-  v0.20
-    19980421   Richard Gooch <rgooch@atnf.csiro.au>
-              Print process command when debugging kerneld/kmod.
-              Added debugging for register/unregister/change operations.
-    19980422   Richard Gooch <rgooch@atnf.csiro.au>
-              Added "devfs=" boot options.
-  v0.21
-    19980426   Richard Gooch <rgooch@atnf.csiro.au>
-              No longer lock/unlock superblock in <devfs_put_super>.
-              Drop negative dentries when they are released.
-              Manage dcache more efficiently.
-  v0.22
-    19980427   Richard Gooch <rgooch@atnf.csiro.au>
-              Added DEVFS_FL_AUTO_DEVNUM flag.
-  v0.23
-    19980430   Richard Gooch <rgooch@atnf.csiro.au>
-              No longer set unnecessary methods.
-  v0.24
-    19980504   Richard Gooch <rgooch@atnf.csiro.au>
-              Added PID display to <call_kerneld> debugging message.
-              Added "after" debugging message to <call_kerneld>.
-    19980519   Richard Gooch <rgooch@atnf.csiro.au>
-              Added "diread" and "diwrite" boot options.
-    19980520   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed persistence problem with permissions.
-  v0.25
-    19980602   Richard Gooch <rgooch@atnf.csiro.au>
-              Support legacy device nodes.
-              Fixed bug where recreated inodes were hidden.
-  v0.26
-    19980602   Richard Gooch <rgooch@atnf.csiro.au>
-              Improved debugging in <get_vfs_inode>.
-    19980607   Richard Gooch <rgooch@atnf.csiro.au>
-              No longer free old dentries in <devfs_mk_dir>.
-              Free all dentries for a given entry when deleting inodes.
-  v0.27
-    19980627   Richard Gooch <rgooch@atnf.csiro.au>
-              Limit auto-device numbering to majors 128 to 239.
-  v0.28
-    19980629   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed inode times persistence problem.
-  v0.29
-    19980704   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed spelling in <devfs_readlink> debug.
-              Fixed bug in <devfs_setup> parsing "dilookup".
-  v0.30
-    19980705   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed devfs inode leak when manually recreating inodes.
-              Fixed permission persistence problem when recreating inodes.
-  v0.31
-    19980727   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed harmless "unused variable" compiler warning.
-              Fixed modes for manually recreated device nodes.
-  v0.32
-    19980728   Richard Gooch <rgooch@atnf.csiro.au>
-              Added NULL devfs inode warning in <devfs_read_inode>.
-              Force all inode nlink values to 1.
-  v0.33
-    19980730   Richard Gooch <rgooch@atnf.csiro.au>
-              Added "dimknod" boot option.
-              Set inode nlink to 0 when freeing dentries.
-              Fixed modes for manually recreated symlinks.
-  v0.34
-    19980802   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed bugs in recreated directories and symlinks.
-  v0.35
-    19980806   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed bugs in recreated device nodes.
-    19980807   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed bug in currently unused <devfs_get_handle_from_inode>.
-              Defined new <devfs_handle_t> type.
-              Improved debugging when getting entries.
-              Fixed bug where directories could be emptied.
-  v0.36
-    19980809   Richard Gooch <rgooch@atnf.csiro.au>
-              Replaced dummy .epoch inode with .devfsd character device.
-    19980810   Richard Gooch <rgooch@atnf.csiro.au>
-              Implemented devfsd protocol revision 0.
-  v0.37
-    19980819   Richard Gooch <rgooch@atnf.csiro.au>
-              Added soothing message to warning in <devfs_d_iput>.
-  v0.38
-    19980829   Richard Gooch <rgooch@atnf.csiro.au>
-              Use GCC extensions for structure initialisations.
-              Implemented async open notification.
-              Incremented devfsd protocol revision to 1.
-  v0.39
-    19980908   Richard Gooch <rgooch@atnf.csiro.au>
-              Moved async open notification to end of <devfs_open>.
-  v0.40
-    19980910   Richard Gooch <rgooch@atnf.csiro.au>
-              Prepended "/dev/" to module load request.
-              Renamed <call_kerneld> to <call_kmod>.
-  v0.41
-    19980910   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed typo "AYSNC" -> "ASYNC".
-  v0.42
-    19980910   Richard Gooch <rgooch@atnf.csiro.au>
-              Added open flag for files.
-  v0.43
-    19980927   Richard Gooch <rgooch@atnf.csiro.au>
-              Set i_blocks=0 and i_blksize=1024 in <devfs_read_inode>.
-  v0.44
-    19981005   Richard Gooch <rgooch@atnf.csiro.au>
-              Added test for empty <<name>> in <devfs_find_handle>.
-              Renamed <generate_path> to <devfs_generate_path> and published.
-  v0.45
-    19981006   Richard Gooch <rgooch@atnf.csiro.au>
-              Created <devfs_get_fops>.
-  v0.46
-    19981007   Richard Gooch <rgooch@atnf.csiro.au>
-              Limit auto-device numbering to majors 144 to 239.
-  v0.47
-    19981010   Richard Gooch <rgooch@atnf.csiro.au>
-              Updated <devfs_follow_link> for VFS change in 2.1.125.
-  v0.48
-    19981022   Richard Gooch <rgooch@atnf.csiro.au>
-              Created DEVFS_ FL_COMPAT flag.
-  v0.49
-    19981023   Richard Gooch <rgooch@atnf.csiro.au>
-              Created "nocompat" boot option.
-  v0.50
-    19981025   Richard Gooch <rgooch@atnf.csiro.au>
-              Replaced "mount" boot option with "nomount".
-  v0.51
-    19981110   Richard Gooch <rgooch@atnf.csiro.au>
-              Created "only" boot option.
-  v0.52
-    19981112   Richard Gooch <rgooch@atnf.csiro.au>
-              Added DEVFS_FL_REMOVABLE flag.
-  v0.53
-    19981114   Richard Gooch <rgooch@atnf.csiro.au>
-              Only call <scan_dir_for_removable> on first call to
-              <devfs_readdir>.
-  v0.54
-    19981205   Richard Gooch <rgooch@atnf.csiro.au>
-              Updated <devfs_rmdir> for VFS change in 2.1.131.
-  v0.55
-    19981218   Richard Gooch <rgooch@atnf.csiro.au>
-              Created <devfs_mk_compat>.
-    19981220   Richard Gooch <rgooch@atnf.csiro.au>
-              Check for partitions on removable media in <devfs_lookup>.
-  v0.56
-    19990118   Richard Gooch <rgooch@atnf.csiro.au>
-              Added support for registering regular files.
-              Created <devfs_set_file_size>.
-              Update devfs inodes from entries if not changed through FS.
-  v0.57
-    19990124   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed <devfs_fill_file> to only initialise temporary inodes.
-              Trap for NULL fops in <devfs_register>.
-              Return -ENODEV in <devfs_fill_file> for non-driver inodes.
-  v0.58
-    19990126   Richard Gooch <rgooch@atnf.csiro.au>
-              Switched from PATH_MAX to DEVFS_PATHLEN.
-  v0.59
-    19990127   Richard Gooch <rgooch@atnf.csiro.au>
-              Created "nottycompat" boot option.
-  v0.60
-    19990318   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed <devfsd_read> to not overrun event buffer.
-  v0.61
-    19990329   Richard Gooch <rgooch@atnf.csiro.au>
-              Created <devfs_auto_unregister>.
-  v0.62
-    19990330   Richard Gooch <rgooch@atnf.csiro.au>
-              Don't return unregistred entries in <devfs_find_handle>.
-              Panic in <devfs_unregister> if entry unregistered.
-    19990401   Richard Gooch <rgooch@atnf.csiro.au>
-              Don't panic in <devfs_auto_unregister> for duplicates.
-  v0.63
-    19990402   Richard Gooch <rgooch@atnf.csiro.au>
-              Don't unregister already unregistered entries in <unregister>.
-  v0.64
-    19990510   Richard Gooch <rgooch@atnf.csiro.au>
-              Disable warning messages when unable to read partition table for
-              removable media.
-  v0.65
-    19990512   Richard Gooch <rgooch@atnf.csiro.au>
-              Updated <devfs_lookup> for VFS change in 2.3.1-pre1.
-              Created "oops-on-panic" boot option.
-              Improved debugging in <devfs_register> and <devfs_unregister>.
-  v0.66
-    19990519   Richard Gooch <rgooch@atnf.csiro.au>
-              Added documentation for some functions.
-    19990525   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed "oops-on-panic" boot option: now always Oops.
-  v0.67
-    19990531   Richard Gooch <rgooch@atnf.csiro.au>
-              Improved debugging in <devfs_register>.
-  v0.68
-    19990604   Richard Gooch <rgooch@atnf.csiro.au>
-              Added "diunlink" and "nokmod" boot options.
-              Removed superfluous warning message in <devfs_d_iput>.
-  v0.69
-    19990611   Richard Gooch <rgooch@atnf.csiro.au>
-              Took account of change to <d_alloc_root>.
-  v0.70
-    19990614   Richard Gooch <rgooch@atnf.csiro.au>
-              Created separate event queue for each mounted devfs.
-              Removed <devfs_invalidate_dcache>.
-              Created new ioctl()s.
-              Incremented devfsd protocol revision to 3.
-              Fixed bug when re-creating directories: contents were lost.
-              Block access to inodes until devfsd updates permissions.
-    19990615   Richard Gooch <rgooch@atnf.csiro.au>
-              Support 2.2.x kernels.
-  v0.71
-    19990623   Richard Gooch <rgooch@atnf.csiro.au>
-              Switched to sending process uid/gid to devfsd.
-              Renamed <call_kmod> to <try_modload>.
-              Added DEVFSD_NOTIFY_LOOKUP event.
-    19990624   Richard Gooch <rgooch@atnf.csiro.au>
-              Added DEVFSD_NOTIFY_CHANGE event.
-              Incremented devfsd protocol revision to 4.
-  v0.72
-    19990713   Richard Gooch <rgooch@atnf.csiro.au>
-              Return EISDIR rather than EINVAL for read(2) on directories.
-  v0.73
-    19990809   Richard Gooch <rgooch@atnf.csiro.au>
-              Changed <devfs_setup> to new __init scheme.
-  v0.74
-    19990901   Richard Gooch <rgooch@atnf.csiro.au>
-              Changed remaining function declarations to new __init scheme.
-  v0.75
-    19991013   Richard Gooch <rgooch@atnf.csiro.au>
-              Created <devfs_get_info>, <devfs_set_info>,
-              <devfs_get_first_child> and <devfs_get_next_sibling>.
-              Added <<dir>> parameter to <devfs_register>, <devfs_mk_compat>,
-              <devfs_mk_dir> and <devfs_find_handle>.
-              Work sponsored by SGI.
-  v0.76
-    19991017   Richard Gooch <rgooch@atnf.csiro.au>
-              Allow multiple unregistrations.
-              Work sponsored by SGI.
-  v0.77
-    19991026   Richard Gooch <rgooch@atnf.csiro.au>
-              Added major and minor number to devfsd protocol.
-              Incremented devfsd protocol revision to 5.
-              Work sponsored by SGI.
-  v0.78
-    19991030   Richard Gooch <rgooch@atnf.csiro.au>
-              Support info pointer for all devfs entry types.
-              Added <<info>> parameter to <devfs_mk_dir> and
-              <devfs_mk_symlink>.
-              Work sponsored by SGI.
-  v0.79
-    19991031   Richard Gooch <rgooch@atnf.csiro.au>
-              Support "../" when searching devfs namespace.
-              Work sponsored by SGI.
-  v0.80
-    19991101   Richard Gooch <rgooch@atnf.csiro.au>
-              Created <devfs_get_unregister_slave>.
-              Work sponsored by SGI.
-  v0.81
-    19991103   Richard Gooch <rgooch@atnf.csiro.au>
-              Exported <devfs_get_parent>.
-              Work sponsored by SGI.
-  v0.82
-    19991104   Richard Gooch <rgooch@atnf.csiro.au>
-               Removed unused <devfs_set_symlink_destination>.
-    19991105   Richard Gooch <rgooch@atnf.csiro.au>
-               Do not hide entries from devfsd or children.
-              Removed DEVFS_ FL_TTY_COMPAT flag.
-              Removed "nottycompat" boot option.
-              Removed <devfs_mk_compat>.
-              Work sponsored by SGI.
-  v0.83
-    19991107   Richard Gooch <rgooch@atnf.csiro.au>
-              Added DEVFS_FL_WAIT flag.
-              Work sponsored by SGI.
-  v0.84
-    19991107   Richard Gooch <rgooch@atnf.csiro.au>
-              Support new "disc" naming scheme in <get_removable_partition>.
-              Allow NULL fops in <devfs_register>.
-              Work sponsored by SGI.
-  v0.85
-    19991110   Richard Gooch <rgooch@atnf.csiro.au>
-              Fall back to major table if NULL fops given to <devfs_register>.
-              Work sponsored by SGI.
-  v0.86
-    19991204   Richard Gooch <rgooch@atnf.csiro.au>
-              Support fifos when unregistering.
-              Work sponsored by SGI.
-  v0.87
-    19991209   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed obsolete DEVFS_ FL_COMPAT and DEVFS_ FL_TOLERANT flags.
-              Work sponsored by SGI.
-  v0.88
-    19991214   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed kmod support.
-              Work sponsored by SGI.
-  v0.89
-    19991216   Richard Gooch <rgooch@atnf.csiro.au>
-              Improved debugging in <get_vfs_inode>.
-              Ensure dentries created by devfsd will be cleaned up.
-              Work sponsored by SGI.
-  v0.90
-    19991223   Richard Gooch <rgooch@atnf.csiro.au>
-              Created <devfs_get_name>.
-              Work sponsored by SGI.
-  v0.91
-    20000203   Richard Gooch <rgooch@atnf.csiro.au>
-              Ported to kernel 2.3.42.
-              Removed <devfs_fill_file>.
-              Work sponsored by SGI.
-  v0.92
-    20000306   Richard Gooch <rgooch@atnf.csiro.au>
-              Added DEVFS_ FL_NO_PERSISTENCE flag.
-              Removed unnecessary call to <update_devfs_inode_from_entry> in
-              <devfs_readdir>.
-              Work sponsored by SGI.
-  v0.93
-    20000413   Richard Gooch <rgooch@atnf.csiro.au>
-              Set inode->i_size to correct size for symlinks.
-    20000414   Richard Gooch <rgooch@atnf.csiro.au>
-              Only give lookup() method to directories to comply with new VFS
-              assumptions.
-              Work sponsored by SGI.
-    20000415   Richard Gooch <rgooch@atnf.csiro.au>
-              Remove unnecessary tests in symlink methods.
-              Don't kill existing block ops in <devfs_read_inode>.
-              Work sponsored by SGI.
-  v0.94
-    20000424   Richard Gooch <rgooch@atnf.csiro.au>
-              Don't create missing directories in <devfs_find_handle>.
-              Work sponsored by SGI.
-  v0.95
-    20000430   Richard Gooch <rgooch@atnf.csiro.au>
-              Added CONFIG_DEVFS_MOUNT.
-              Work sponsored by SGI.
-  v0.96
-    20000608   Richard Gooch <rgooch@atnf.csiro.au>
-              Disabled multi-mount capability (use VFS bindings instead).
-              Work sponsored by SGI.
-  v0.97
-    20000610   Richard Gooch <rgooch@atnf.csiro.au>
-              Switched to FS_SINGLE to disable multi-mounts.
-    20000612   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed module support.
-              Removed multi-mount code.
-              Removed compatibility macros: VFS has changed too much.
-              Work sponsored by SGI.
-  v0.98
-    20000614   Richard Gooch <rgooch@atnf.csiro.au>
-              Merged devfs inode into devfs entry.
-              Work sponsored by SGI.
-  v0.99
-    20000619   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed dead code in <devfs_register> which used to call
-              <free_dentries>.
-              Work sponsored by SGI.
-  v0.100
-    20000621   Richard Gooch <rgooch@atnf.csiro.au>
-              Changed interface to <devfs_register>.
-              Work sponsored by SGI.
-  v0.101
-    20000622   Richard Gooch <rgooch@atnf.csiro.au>
-              Simplified interface to <devfs_mk_symlink> and <devfs_mk_dir>.
-              Simplified interface to <devfs_find_handle>.
-              Work sponsored by SGI.
-  v0.102
-    20010519   Richard Gooch <rgooch@atnf.csiro.au>
-              Ensure <devfs_generate_path> terminates string for root entry.
-              Exported <devfs_get_name> to modules.
-    20010520   Richard Gooch <rgooch@atnf.csiro.au>
-              Make <devfs_mk_symlink> send events to devfsd.
-              Cleaned up option processing in <devfs_setup>.
-    20010521   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed bugs in handling symlinks: could leak or cause Oops.
-    20010522   Richard Gooch <rgooch@atnf.csiro.au>
-              Cleaned up directory handling by separating fops.
-  v0.103
-    20010601   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed handling of inverted options in <devfs_setup>.
-  v0.104
-    20010604   Richard Gooch <rgooch@atnf.csiro.au>
-              Adjusted <try_modload> to account for <devfs_generate_path> fix.
-  v0.105
-    20010617   Richard Gooch <rgooch@atnf.csiro.au>
-              Answered question posed by Al Viro and removed his comments.
-              Moved setting of registered flag after other fields are changed.
-              Fixed race between <devfsd_close> and <devfsd_notify_one>.
-              Global VFS changes added bogus BKL to <devfsd_close>: removed.
-              Widened locking in <devfs_readlink> and <devfs_follow_link>.
-              Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc.
-              Simplified locking in <devfsd_ioctl> and fixed memory leak.
-  v0.106
-    20010709   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed broken devnum allocation and use <devfs_alloc_devnum>.
-              Fixed old devnum leak by calling new <devfs_dealloc_devnum>.
-  v0.107
-    20010712   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed bug in <devfs_setup> which could hang boot process.
-  v0.108
-    20010730   Richard Gooch <rgooch@atnf.csiro.au>
-              Added DEVFSD_NOTIFY_DELETE event.
-    20010801   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed #include <asm/segment.h>.
-  v0.109
-    20010807   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed inode table races by removing it and using
-              inode->u.generic_ip instead.
-              Moved <devfs_read_inode> into <get_vfs_inode>.
-              Moved <devfs_write_inode> into <devfs_notify_change>.
-  v0.110
-    20010808   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed race in <devfs_do_symlink> for uni-processor.
-  v0.111
-    20010818   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed remnant of multi-mount support in <devfs_mknod>.
-               Removed unused DEVFS_FL_SHOW_UNREG flag.
-  v0.112
-    20010820   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed nlink field from struct devfs_inode.
-  v0.113
-    20010823   Richard Gooch <rgooch@atnf.csiro.au>
-              Replaced BKL with global rwsem to protect symlink data (quick
-              and dirty hack).
-  v0.114
-    20010827   Richard Gooch <rgooch@atnf.csiro.au>
-              Replaced global rwsem for symlink with per-link refcount.
-  v0.115
-    20010919   Richard Gooch <rgooch@atnf.csiro.au>
-              Set inode->i_mapping->a_ops for block nodes in <get_vfs_inode>.
-  v0.116
-    20011008   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed overrun in <devfs_link> by removing function (not needed).
-    20011009   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed buffer underrun in <try_modload>.
-    20011029   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed race in <devfsd_ioctl> when setting event mask.
-    20011114   Richard Gooch <rgooch@atnf.csiro.au>
-              First release of new locking code.
-  v1.0
-    20011117   Richard Gooch <rgooch@atnf.csiro.au>
-              Discard temporary buffer, now use "%s" for dentry names.
-    20011118   Richard Gooch <rgooch@atnf.csiro.au>
-              Don't generate path in <try_modload>: use fake entry instead.
-              Use "existing" directory in <_devfs_make_parent_for_leaf>.
-    20011122   Richard Gooch <rgooch@atnf.csiro.au>
-              Use slab cache rather than fixed buffer for devfsd events.
-  v1.1
-    20011125   Richard Gooch <rgooch@atnf.csiro.au>
-              Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>.
-    20011127   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed locking bug in <devfs_d_revalidate_wait> due to typo.
-              Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from
-              devfsd or children.
-  v1.2
-    20011202   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed bug in <devfsd_read>: was dereferencing freed pointer.
-  v1.3
-    20011203   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed bug in <devfsd_close>: was dereferencing freed pointer.
-              Added process group check for devfsd privileges.
-  v1.4
-    20011204   Richard Gooch <rgooch@atnf.csiro.au>
-              Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>.
-  v1.5
-    20011211   Richard Gooch <rgooch@atnf.csiro.au>
-              Return old entry in <devfs_mk_dir> for 2.4.x kernels.
-    20011212   Richard Gooch <rgooch@atnf.csiro.au>
-              Increment refcount on module in <check_disc_changed>.
-    20011215   Richard Gooch <rgooch@atnf.csiro.au>
-              Created <devfs_get_handle> and exported <devfs_put>.
-              Increment refcount on module in <devfs_get_ops>.
-              Created <devfs_put_ops>.
-  v1.6
-    20011216   Richard Gooch <rgooch@atnf.csiro.au>
-              Added poisoning to <devfs_put>.
-              Improved debugging messages.
-  v1.7
-    20011221   Richard Gooch <rgooch@atnf.csiro.au>
-              Corrected (made useful) debugging message in <unregister>.
-              Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs>
-    20011224   Richard Gooch <rgooch@atnf.csiro.au>
-              Added magic number to guard against scribbling drivers.
-    20011226   Richard Gooch <rgooch@atnf.csiro.au>
-              Only return old entry in <devfs_mk_dir> if a directory.
-              Defined macros for error and debug messages.
-  v1.8
-    20020113   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed (rare, old) race in <devfs_lookup>.
-  v1.9
-    20020120   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed deadlock bug in <devfs_d_revalidate_wait>.
-              Tag VFS deletable in <devfs_mk_symlink> if handle ignored.
-  v1.10
-    20020129   Richard Gooch <rgooch@atnf.csiro.au>
-              Added KERN_* to remaining messages.
-              Cleaned up declaration of <stat_read>.
-  v1.11
-    20020219   Richard Gooch <rgooch@atnf.csiro.au>
-              Changed <devfs_rmdir> to allow later additions if not yet empty.
-  v1.12
-    20020406   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed silently introduced calls to lock_kernel() and
-              unlock_kernel() due to recent VFS locking changes. BKL isn't
-              required in devfs.
-  v1.13
-    20020428   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed 2.4.x compatibility code.
-  v1.14
-    20020510   Richard Gooch <rgooch@atnf.csiro.au>
-              Added BKL to <devfs_open> because drivers still need it.
-  v1.15
-    20020512   Richard Gooch <rgooch@atnf.csiro.au>
-              Protected <scan_dir_for_removable> and <get_removable_partition>
-              from changing directory contents.
-  v1.16
-    20020514   Richard Gooch <rgooch@atnf.csiro.au>
-              Minor cleanup of <scan_dir_for_removable>.
-  v1.17
-    20020721   Richard Gooch <rgooch@atnf.csiro.au>
-              Switched to ISO C structure field initialisers.
-              Switch to set_current_state() and move before add_wait_queue().
-    20020722   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed devfs entry leak in <devfs_readdir> when *readdir fails.
-  v1.18
-    20020725   Richard Gooch <rgooch@atnf.csiro.au>
-              Created <devfs_find_and_unregister>.
-  v1.19
-    20020728   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed deprecated <devfs_find_handle>.
-  v1.20
-    20020820   Richard Gooch <rgooch@atnf.csiro.au>
-              Fixed module unload race in <devfs_open>.
-  v1.21
-    20021013   Richard Gooch <rgooch@atnf.csiro.au>
-              Removed DEVFS_ FL_AUTO_OWNER.
-              Switched lingering structure field initialiser to ISO C.
-              Added locking when updating FCB flags.
-  v1.22
-*/
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/time.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/devfs_fs.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/smp_lock.h>
-#include <linux/smp.h>
-#include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/namei.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/atomic.h>
-
-#define DEVFS_VERSION            "2004-01-31"
-
-#define DEVFS_NAME "devfs"
-
-#define FIRST_INODE 1
-
-#define STRING_LENGTH 256
-#define FAKE_BLOCK_SIZE 1024
-#define POISON_PTR ( *(void **) poison_array )
-#define MAGIC_VALUE 0x327db823
-
-#ifndef TRUE
-#  define TRUE 1
-#  define FALSE 0
-#endif
-
-#define MODE_DIR (S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO)
-
-#define DEBUG_NONE         0x0000000
-#define DEBUG_MODULE_LOAD  0x0000001
-#define DEBUG_REGISTER     0x0000002
-#define DEBUG_UNREGISTER   0x0000004
-#define DEBUG_FREE         0x0000008
-#define DEBUG_SET_FLAGS    0x0000010
-#define DEBUG_S_READ       0x0000100   /*  Break  */
-#define DEBUG_I_LOOKUP     0x0001000   /*  Break  */
-#define DEBUG_I_CREATE     0x0002000
-#define DEBUG_I_GET        0x0004000
-#define DEBUG_I_CHANGE     0x0008000
-#define DEBUG_I_UNLINK     0x0010000
-#define DEBUG_I_RLINK      0x0020000
-#define DEBUG_I_FLINK      0x0040000
-#define DEBUG_I_MKNOD      0x0080000
-#define DEBUG_F_READDIR    0x0100000   /*  Break  */
-#define DEBUG_D_DELETE     0x1000000   /*  Break  */
-#define DEBUG_D_RELEASE    0x2000000
-#define DEBUG_D_IPUT       0x4000000
-#define DEBUG_ALL          0xfffffff
-#define DEBUG_DISABLED     DEBUG_NONE
-
-#define OPTION_NONE             0x00
-#define OPTION_MOUNT            0x01
-
-#define PRINTK(format, args...) \
-   {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);}
-
-#define OOPS(format, args...) \
-   {printk (KERN_CRIT "%s" format, __FUNCTION__ , ## args); \
-    printk ("Forcing Oops\n"); \
-    BUG();}
-
-#ifdef CONFIG_DEVFS_DEBUG
-#  define VERIFY_ENTRY(de) \
-   {if ((de) && (de)->magic_number != MAGIC_VALUE) \
-        OOPS ("(%p): bad magic value: %x\n", (de), (de)->magic_number);}
-#  define WRITE_ENTRY_MAGIC(de,magic) (de)->magic_number = (magic)
-#  define DPRINTK(flag, format, args...) \
-   {if (devfs_debug & flag) \
-       printk (KERN_INFO "%s" format, __FUNCTION__ , ## args);}
-#else
-#  define VERIFY_ENTRY(de)
-#  define WRITE_ENTRY_MAGIC(de,magic)
-#  define DPRINTK(flag, format, args...)
-#endif
-
-typedef struct devfs_entry *devfs_handle_t;
-
-struct directory_type {
-       rwlock_t lock;          /*  Lock for searching(R)/updating(W)   */
-       struct devfs_entry *first;
-       struct devfs_entry *last;
-       unsigned char no_more_additions:1;
-};
-
-struct symlink_type {
-       unsigned int length;    /*  Not including the NULL-termimator       */
-       char *linkname;         /*  This is NULL-terminated                 */
-};
-
-struct devfs_inode {           /*  This structure is for "persistent" inode storage  */
-       struct dentry *dentry;
-       struct timespec atime;
-       struct timespec mtime;
-       struct timespec ctime;
-       unsigned int ino;       /*  Inode number as seen in the VFS         */
-       uid_t uid;
-       gid_t gid;
-};
-
-struct devfs_entry {
-#ifdef CONFIG_DEVFS_DEBUG
-       unsigned int magic_number;
-#endif
-       void *info;
-       atomic_t refcount;      /*  When this drops to zero, it's unused    */
-       union {
-               struct directory_type dir;
-               dev_t dev;
-               struct symlink_type symlink;
-               const char *name;       /*  Only used for (mode == 0)               */
-       } u;
-       struct devfs_entry *prev;       /*  Previous entry in the parent directory  */
-       struct devfs_entry *next;       /*  Next entry in the parent directory      */
-       struct devfs_entry *parent;     /*  The parent directory                    */
-       struct devfs_inode inode;
-       umode_t mode;
-       unsigned short namelen; /*  I think 64k+ filenames are a way off... */
-       unsigned char vfs:1;    /*  Whether the VFS may delete the entry   */
-       char name[1];           /*  This is just a dummy: the allocated array
-                                  is bigger. This is NULL-terminated      */
-};
-
-/*  The root of the device tree  */
-static struct devfs_entry *root_entry;
-
-struct devfsd_buf_entry {
-       struct devfs_entry *de; /*  The name is generated with this         */
-       unsigned short type;    /*  The type of event                       */
-       umode_t mode;
-       uid_t uid;
-       gid_t gid;
-       struct devfsd_buf_entry *next;
-};
-
-struct fs_info {               /*  This structure is for the mounted devfs  */
-       struct super_block *sb;
-       spinlock_t devfsd_buffer_lock;  /*  Lock when inserting/deleting events  */
-       struct devfsd_buf_entry *devfsd_first_event;
-       struct devfsd_buf_entry *devfsd_last_event;
-       volatile int devfsd_sleeping;
-       volatile struct task_struct *devfsd_task;
-       volatile pid_t devfsd_pgrp;
-       volatile struct file *devfsd_file;
-       struct devfsd_notify_struct *devfsd_info;
-       volatile unsigned long devfsd_event_mask;
-       atomic_t devfsd_overrun_count;
-       wait_queue_head_t devfsd_wait_queue;    /*  Wake devfsd on input       */
-       wait_queue_head_t revalidate_wait_queue;        /*  Wake when devfsd sleeps    */
-};
-
-static struct fs_info fs_info = {.devfsd_buffer_lock = SPIN_LOCK_UNLOCKED };
-static kmem_cache_t *devfsd_buf_cache;
-#ifdef CONFIG_DEVFS_DEBUG
-static unsigned int devfs_debug_init __initdata = DEBUG_NONE;
-static unsigned int devfs_debug = DEBUG_NONE;
-static DEFINE_SPINLOCK(stat_lock);
-static unsigned int stat_num_entries;
-static unsigned int stat_num_bytes;
-#endif
-static unsigned char poison_array[8] =
-    { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a };
-
-#ifdef CONFIG_DEVFS_MOUNT
-static unsigned int boot_options = OPTION_MOUNT;
-#else
-static unsigned int boot_options = OPTION_NONE;
-#endif
-
-/*  Forward function declarations  */
-static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir,
-                                      const char *name, int namelen,
-                                      int traverse_symlink);
-static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len,
-                          loff_t * ppos);
-static int devfsd_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg);
-static int devfsd_close(struct inode *inode, struct file *file);
-#ifdef CONFIG_DEVFS_DEBUG
-static ssize_t stat_read(struct file *file, char __user *buf, size_t len,
-                        loff_t * ppos);
-static const struct file_operations stat_fops = {
-       .open = nonseekable_open,
-       .read = stat_read,
-};
-#endif
-
-/*  Devfs daemon file operations  */
-static const struct file_operations devfsd_fops = {
-       .open = nonseekable_open,
-       .read = devfsd_read,
-       .ioctl = devfsd_ioctl,
-       .release = devfsd_close,
-};
-
-/*  Support functions follow  */
-
-/**
- *     devfs_get - Get a reference to a devfs entry.
- *     @de:  The devfs entry.
- */
-
-static struct devfs_entry *devfs_get(struct devfs_entry *de)
-{
-       VERIFY_ENTRY(de);
-       if (de)
-               atomic_inc(&de->refcount);
-       return de;
-}                              /*  End Function devfs_get  */
-
-/**
- *     devfs_put - Put (release) a reference to a devfs entry.
- *     @de:  The handle to the devfs entry.
- */
-
-static void devfs_put(devfs_handle_t de)
-{
-       if (!de)
-               return;
-       VERIFY_ENTRY(de);
-       if (de->info == POISON_PTR)
-               OOPS("(%p): poisoned pointer\n", de);
-       if (!atomic_dec_and_test(&de->refcount))
-               return;
-       if (de == root_entry)
-               OOPS("(%p): root entry being freed\n", de);
-       DPRINTK(DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n",
-               de->name, de, de->parent,
-               de->parent ? de->parent->name : "no parent");
-       if (S_ISLNK(de->mode))
-               kfree(de->u.symlink.linkname);
-       WRITE_ENTRY_MAGIC(de, 0);
-#ifdef CONFIG_DEVFS_DEBUG
-       spin_lock(&stat_lock);
-       --stat_num_entries;
-       stat_num_bytes -= sizeof *de + de->namelen;
-       if (S_ISLNK(de->mode))
-               stat_num_bytes -= de->u.symlink.length + 1;
-       spin_unlock(&stat_lock);
-#endif
-       de->info = POISON_PTR;
-       kfree(de);
-}                              /*  End Function devfs_put  */
-
-/**
- *     _devfs_search_dir - Search for a devfs entry in a directory.
- *     @dir:  The directory to search.
- *     @name:  The name of the entry to search for.
- *     @namelen:  The number of characters in @name.
- *
- *  Search for a devfs entry in a directory and returns a pointer to the entry
- *   on success, else %NULL. The directory must be locked already.
- *   An implicit devfs_get() is performed on the returned entry.
- */
-
-static struct devfs_entry *_devfs_search_dir(struct devfs_entry *dir,
-                                            const char *name,
-                                            unsigned int namelen)
-{
-       struct devfs_entry *curr;
-
-       if (!S_ISDIR(dir->mode)) {
-               PRINTK("(%s): not a directory\n", dir->name);
-               return NULL;
-       }
-       for (curr = dir->u.dir.first; curr != NULL; curr = curr->next) {
-               if (curr->namelen != namelen)
-                       continue;
-               if (memcmp(curr->name, name, namelen) == 0)
-                       break;
-               /*  Not found: try the next one  */
-       }
-       return devfs_get(curr);
-}                              /*  End Function _devfs_search_dir  */
-
-/**
- *     _devfs_alloc_entry - Allocate a devfs entry.
- *     @name:     the name of the entry
- *     @namelen:  the number of characters in @name
- *      @mode:     the mode for the entry
- *
- *  Allocate a devfs entry and returns a pointer to the entry on success, else
- *   %NULL.
- */
-
-static struct devfs_entry *_devfs_alloc_entry(const char *name,
-                                             unsigned int namelen,
-                                             umode_t mode)
-{
-       struct devfs_entry *new;
-       static unsigned long inode_counter = FIRST_INODE;
-       static DEFINE_SPINLOCK(counter_lock);
-
-       if (name && (namelen < 1))
-               namelen = strlen(name);
-       if ((new = kmalloc(sizeof *new + namelen, GFP_KERNEL)) == NULL)
-               return NULL;
-       memset(new, 0, sizeof *new + namelen);  /*  Will set '\0' on name  */
-       new->mode = mode;
-       if (S_ISDIR(mode))
-               rwlock_init(&new->u.dir.lock);
-       atomic_set(&new->refcount, 1);
-       spin_lock(&counter_lock);
-       new->inode.ino = inode_counter++;
-       spin_unlock(&counter_lock);
-       if (name)
-               memcpy(new->name, name, namelen);
-       new->namelen = namelen;
-       WRITE_ENTRY_MAGIC(new, MAGIC_VALUE);
-#ifdef CONFIG_DEVFS_DEBUG
-       spin_lock(&stat_lock);
-       ++stat_num_entries;
-       stat_num_bytes += sizeof *new + namelen;
-       spin_unlock(&stat_lock);
-#endif
-       return new;
-}                              /*  End Function _devfs_alloc_entry  */
-
-/**
- *     _devfs_append_entry - Append a devfs entry to a directory's child list.
- *     @dir:  The directory to add to.
- *     @de:  The devfs entry to append.
- *     @old_de: If an existing entry exists, it will be written here. This may
- *              be %NULL. An implicit devfs_get() is performed on this entry.
- *
- *  Append a devfs entry to a directory's list of children, checking first to
- *   see if an entry of the same name exists. The directory will be locked.
- *   The value 0 is returned on success, else a negative error code.
- *   On failure, an implicit devfs_put() is performed on %de.
- */
-
-static int _devfs_append_entry(devfs_handle_t dir, devfs_handle_t de,
-                              devfs_handle_t * old_de)
-{
-       int retval;
-
-       if (old_de)
-               *old_de = NULL;
-       if (!S_ISDIR(dir->mode)) {
-               PRINTK("(%s): dir: \"%s\" is not a directory\n", de->name,
-                      dir->name);
-               devfs_put(de);
-               return -ENOTDIR;
-       }
-       write_lock(&dir->u.dir.lock);
-       if (dir->u.dir.no_more_additions)
-               retval = -ENOENT;
-       else {
-               struct devfs_entry *old;
-
-               old = _devfs_search_dir(dir, de->name, de->namelen);
-               if (old_de)
-                       *old_de = old;
-               else
-                       devfs_put(old);
-               if (old == NULL) {
-                       de->parent = dir;
-                       de->prev = dir->u.dir.last;
-                       /*  Append to the directory's list of children  */
-                       if (dir->u.dir.first == NULL)
-                               dir->u.dir.first = de;
-                       else
-                               dir->u.dir.last->next = de;
-                       dir->u.dir.last = de;
-                       retval = 0;
-               } else
-                       retval = -EEXIST;
-       }
-       write_unlock(&dir->u.dir.lock);
-       if (retval)
-               devfs_put(de);
-       return retval;
-}                              /*  End Function _devfs_append_entry  */
-
-/**
- *     _devfs_get_root_entry - Get the root devfs entry.
- *
- *     Returns the root devfs entry on success, else %NULL.
- *
- *     TODO it must be called asynchronously due to the fact
- *     that devfs is initialized relatively late. Proper way
- *     is to remove module_init from init_devfs_fs and manually
- *     call it early enough during system init
- */
-
-static struct devfs_entry *_devfs_get_root_entry(void)
-{
-       struct devfs_entry *new;
-       static DEFINE_SPINLOCK(root_lock);
-
-       if (root_entry)
-               return root_entry;
-
-       new = _devfs_alloc_entry(NULL, 0, MODE_DIR);
-       if (new == NULL)
-               return NULL;
-
-       spin_lock(&root_lock);
-       if (root_entry) {
-               spin_unlock(&root_lock);
-               devfs_put(new);
-               return root_entry;
-       }
-       root_entry = new;
-       spin_unlock(&root_lock);
-
-       return root_entry;
-}                              /*  End Function _devfs_get_root_entry  */
-
-/**
- *     _devfs_descend - Descend down a tree using the next component name.
- *     @dir:  The directory to search.
- *     @name:  The component name to search for.
- *     @namelen:  The length of %name.
- *     @next_pos:  The position of the next '/' or '\0' is written here.
- *
- *  Descend into a directory, searching for a component. This function forms
- *   the core of a tree-walking algorithm. The directory will be locked.
- *   The devfs entry corresponding to the component is returned. If there is
- *   no matching entry, %NULL is returned.
- *   An implicit devfs_get() is performed on the returned entry.
- */
-
-static struct devfs_entry *_devfs_descend(struct devfs_entry *dir,
-                                         const char *name, int namelen,
-                                         int *next_pos)
-{
-       const char *stop, *ptr;
-       struct devfs_entry *entry;
-
-       if ((namelen >= 3) && (strncmp(name, "../", 3) == 0)) { /*  Special-case going to parent directory  */
-               *next_pos = 3;
-               return devfs_get(dir->parent);
-       }
-       stop = name + namelen;
-       /*  Search for a possible '/'  */
-       for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr) ;
-       *next_pos = ptr - name;
-       read_lock(&dir->u.dir.lock);
-       entry = _devfs_search_dir(dir, name, *next_pos);
-       read_unlock(&dir->u.dir.lock);
-       return entry;
-}                              /*  End Function _devfs_descend  */
-
-static devfs_handle_t _devfs_make_parent_for_leaf(struct devfs_entry *dir,
-                                                 const char *name,
-                                                 int namelen, int *leaf_pos)
-{
-       int next_pos = 0;
-
-       if (dir == NULL)
-               dir = _devfs_get_root_entry();
-       if (dir == NULL)
-               return NULL;
-       devfs_get(dir);
-       /*  Search for possible trailing component and ignore it  */
-       for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen) ;
-       *leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0;
-       for (; namelen > 0; name += next_pos, namelen -= next_pos) {
-               struct devfs_entry *de, *old = NULL;
-
-               if ((de =
-                    _devfs_descend(dir, name, namelen, &next_pos)) == NULL) {
-                       de = _devfs_alloc_entry(name, next_pos, MODE_DIR);
-                       devfs_get(de);
-                       if (!de || _devfs_append_entry(dir, de, &old)) {
-                               devfs_put(de);
-                               if (!old || !S_ISDIR(old->mode)) {
-                                       devfs_put(old);
-                                       devfs_put(dir);
-                                       return NULL;
-                               }
-                               de = old;       /*  Use the existing directory  */
-                       }
-               }
-               if (de == dir->parent) {
-                       devfs_put(dir);
-                       devfs_put(de);
-                       return NULL;
-               }
-               devfs_put(dir);
-               dir = de;
-               if (name[next_pos] == '/')
-                       ++next_pos;
-       }
-       return dir;
-}                              /*  End Function _devfs_make_parent_for_leaf  */
-
-static devfs_handle_t _devfs_prepare_leaf(devfs_handle_t * dir,
-                                         const char *name, umode_t mode)
-{
-       int namelen, leaf_pos;
-       struct devfs_entry *de;
-
-       namelen = strlen(name);
-       if ((*dir = _devfs_make_parent_for_leaf(*dir, name, namelen,
-                                               &leaf_pos)) == NULL) {
-               PRINTK("(%s): could not create parent path\n", name);
-               return NULL;
-       }
-       if ((de = _devfs_alloc_entry(name + leaf_pos, namelen - leaf_pos, mode))
-           == NULL) {
-               PRINTK("(%s): could not allocate entry\n", name);
-               devfs_put(*dir);
-               return NULL;
-       }
-       return de;
-}                              /*  End Function _devfs_prepare_leaf  */
-
-static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir,
-                                      const char *name, int namelen,
-                                      int traverse_symlink)
-{
-       int next_pos = 0;
-
-       if (dir == NULL)
-               dir = _devfs_get_root_entry();
-       if (dir == NULL)
-               return NULL;
-       devfs_get(dir);
-       for (; namelen > 0; name += next_pos, namelen -= next_pos) {
-               struct devfs_entry *de, *link;
-
-               if (!S_ISDIR(dir->mode)) {
-                       devfs_put(dir);
-                       return NULL;
-               }
-
-               if ((de =
-                    _devfs_descend(dir, name, namelen, &next_pos)) == NULL) {
-                       devfs_put(dir);
-                       return NULL;
-               }
-               if (S_ISLNK(de->mode) && traverse_symlink) {    /*  Need to follow the link: this is a stack chomper  */
-                       /* FIXME what if it puts outside of mounted tree? */
-                       link = _devfs_walk_path(dir, de->u.symlink.linkname,
-                                               de->u.symlink.length, TRUE);
-                       devfs_put(de);
-                       if (!link) {
-                               devfs_put(dir);
-                               return NULL;
-                       }
-                       de = link;
-               }
-               devfs_put(dir);
-               dir = de;
-               if (name[next_pos] == '/')
-                       ++next_pos;
-       }
-       return dir;
-}                              /*  End Function _devfs_walk_path  */
-
-/**
- *     _devfs_find_entry - Find a devfs entry.
- *     @dir: The handle to the parent devfs directory entry. If this is %NULL the
- *             name is relative to the root of the devfs.
- *     @name: The name of the entry. This may be %NULL.
- *     @traverse_symlink: If %TRUE then symbolic links are traversed.
- *
- *     Returns the devfs_entry pointer on success, else %NULL. An implicit
- *     devfs_get() is performed.
- */
-
-static struct devfs_entry *_devfs_find_entry(devfs_handle_t dir,
-                                            const char *name,
-                                            int traverse_symlink)
-{
-       unsigned int namelen = strlen(name);
-
-       if (name[0] == '/') {
-               /*  Skip leading pathname component  */
-               if (namelen < 2) {
-                       PRINTK("(%s): too short\n", name);
-                       return NULL;
-               }
-               for (++name, --namelen; (*name != '/') && (namelen > 0);
-                    ++name, --namelen) ;
-               if (namelen < 2) {
-                       PRINTK("(%s): too short\n", name);
-                       return NULL;
-               }
-               ++name;
-               --namelen;
-       }
-       return _devfs_walk_path(dir, name, namelen, traverse_symlink);
-}                              /*  End Function _devfs_find_entry  */
-
-static struct devfs_entry *get_devfs_entry_from_vfs_inode(struct inode *inode)
-{
-       if (inode == NULL)
-               return NULL;
-       VERIFY_ENTRY((struct devfs_entry *)inode->u.generic_ip);
-       return inode->u.generic_ip;
-}                              /*  End Function get_devfs_entry_from_vfs_inode  */
-
-/**
- *     free_dentry - Free the dentry for a device entry and invalidate inode.
- *     @de: The entry.
- *
- *     This must only be called after the entry has been unhooked from its
- *      parent directory.
- */
-
-static void free_dentry(struct devfs_entry *de)
-{
-       struct dentry *dentry = de->inode.dentry;
-
-       if (!dentry)
-               return;
-       spin_lock(&dcache_lock);
-       dget_locked(dentry);
-       spin_unlock(&dcache_lock);
-       /*  Forcefully remove the inode  */
-       if (dentry->d_inode != NULL)
-               dentry->d_inode->i_nlink = 0;
-       d_drop(dentry);
-       dput(dentry);
-}                              /*  End Function free_dentry  */
-
-/**
- *     is_devfsd_or_child - Test if the current process is devfsd or one of its children.
- *     @fs_info: The filesystem information.
- *
- *     Returns %TRUE if devfsd or child, else %FALSE.
- */
-
-static int is_devfsd_or_child(struct fs_info *fs_info)
-{
-       struct task_struct *p = current;
-
-       if (p == fs_info->devfsd_task)
-               return (TRUE);
-       if (process_group(p) == fs_info->devfsd_pgrp)
-               return (TRUE);
-       read_lock(&tasklist_lock);
-       for (; p != &init_task; p = p->real_parent) {
-               if (p == fs_info->devfsd_task) {
-                       read_unlock(&tasklist_lock);
-                       return (TRUE);
-               }
-       }
-       read_unlock(&tasklist_lock);
-       return (FALSE);
-}                              /*  End Function is_devfsd_or_child  */
-
-/**
- *     devfsd_queue_empty - Test if devfsd has work pending in its event queue.
- *     @fs_info: The filesystem information.
- *
- *     Returns %TRUE if the queue is empty, else %FALSE.
- */
-
-static inline int devfsd_queue_empty(struct fs_info *fs_info)
-{
-       return (fs_info->devfsd_last_event) ? FALSE : TRUE;
-}                              /*  End Function devfsd_queue_empty  */
-
-/**
- *     wait_for_devfsd_finished - Wait for devfsd to finish processing its event queue.
- *     @fs_info: The filesystem information.
- *
- *     Returns %TRUE if no more waiting will be required, else %FALSE.
- */
-
-static int wait_for_devfsd_finished(struct fs_info *fs_info)
-{
-       DECLARE_WAITQUEUE(wait, current);
-
-       if (fs_info->devfsd_task == NULL)
-               return (TRUE);
-       if (devfsd_queue_empty(fs_info) && fs_info->devfsd_sleeping)
-               return TRUE;
-       if (is_devfsd_or_child(fs_info))
-               return (FALSE);
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       add_wait_queue(&fs_info->revalidate_wait_queue, &wait);
-       if (!devfsd_queue_empty(fs_info) || !fs_info->devfsd_sleeping)
-               if (fs_info->devfsd_task)
-                       schedule();
-       remove_wait_queue(&fs_info->revalidate_wait_queue, &wait);
-       __set_current_state(TASK_RUNNING);
-       return (TRUE);
-}                              /*  End Function wait_for_devfsd_finished  */
-
-/**
- *     devfsd_notify_de - Notify the devfsd daemon of a change.
- *     @de: The devfs entry that has changed. This and all parent entries will
- *            have their reference counts incremented if the event was queued.
- *     @type: The type of change.
- *     @mode: The mode of the entry.
- *     @uid: The user ID.
- *     @gid: The group ID.
- *     @fs_info: The filesystem info.
- *
- *     Returns %TRUE if an event was queued and devfsd woken up, else %FALSE.
- */
-
-static int devfsd_notify_de(struct devfs_entry *de,
-                           unsigned short type, umode_t mode,
-                           uid_t uid, gid_t gid, struct fs_info *fs_info)
-{
-       struct devfsd_buf_entry *entry;
-       struct devfs_entry *curr;
-
-       if (!(fs_info->devfsd_event_mask & (1 << type)))
-               return (FALSE);
-       if ((entry = kmem_cache_alloc(devfsd_buf_cache, SLAB_KERNEL)) == NULL) {
-               atomic_inc(&fs_info->devfsd_overrun_count);
-               return (FALSE);
-       }
-       for (curr = de; curr != NULL; curr = curr->parent)
-               devfs_get(curr);
-       entry->de = de;
-       entry->type = type;
-       entry->mode = mode;
-       entry->uid = uid;
-       entry->gid = gid;
-       entry->next = NULL;
-       spin_lock(&fs_info->devfsd_buffer_lock);
-       if (!fs_info->devfsd_first_event)
-               fs_info->devfsd_first_event = entry;
-       if (fs_info->devfsd_last_event)
-               fs_info->devfsd_last_event->next = entry;
-       fs_info->devfsd_last_event = entry;
-       spin_unlock(&fs_info->devfsd_buffer_lock);
-       wake_up_interruptible(&fs_info->devfsd_wait_queue);
-       return (TRUE);
-}                              /*  End Function devfsd_notify_de  */
-
-/**
- *     devfsd_notify - Notify the devfsd daemon of a change.
- *     @de: The devfs entry that has changed.
- *     @type: The type of change event.
- *     @wait: If TRUE, the function waits for the daemon to finish processing
- *             the event.
- */
-
-static void devfsd_notify(struct devfs_entry *de, unsigned short type)
-{
-       devfsd_notify_de(de, type, de->mode, current->euid,
-                        current->egid, &fs_info);
-}
-
-static int devfs_mk_dev(dev_t dev, umode_t mode, const char *fmt, va_list args)
-{
-       struct devfs_entry *dir = NULL, *de;
-       char buf[64];
-       int error, n;
-
-       n = vsnprintf(buf, sizeof(buf), fmt, args);
-       if (n >= sizeof(buf) || !buf[0]) {
-               printk(KERN_WARNING "%s: invalid format string %s\n",
-                      __FUNCTION__, fmt);
-               return -EINVAL;
-       }
-
-       de = _devfs_prepare_leaf(&dir, buf, mode);
-       if (!de) {
-               printk(KERN_WARNING "%s: could not prepare leaf for %s\n",
-                      __FUNCTION__, buf);
-               return -ENOMEM; /* could be more accurate... */
-       }
-
-       de->u.dev = dev;
-
-       error = _devfs_append_entry(dir, de, NULL);
-       if (error) {
-               printk(KERN_WARNING "%s: could not append to parent for %s\n",
-                      __FUNCTION__, buf);
-               goto out;
-       }
-
-       devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);
-      out:
-       devfs_put(dir);
-       return error;
-}
-
-int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
-{
-       va_list args;
-
-       if (!S_ISBLK(mode)) {
-               printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",
-                      __FUNCTION__, mode, fmt);
-               return -EINVAL;
-       }
-
-       va_start(args, fmt);
-       return devfs_mk_dev(dev, mode, fmt, args);
-}
-
-EXPORT_SYMBOL(devfs_mk_bdev);
-
-int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...)
-{
-       va_list args;
-
-       if (!S_ISCHR(mode)) {
-               printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",
-                      __FUNCTION__, mode, fmt);
-               return -EINVAL;
-       }
-
-       va_start(args, fmt);
-       return devfs_mk_dev(dev, mode, fmt, args);
-}
-
-EXPORT_SYMBOL(devfs_mk_cdev);
-
-/**
- *     _devfs_unhook - Unhook a device entry from its parents list
- *     @de: The entry to unhook.
- *
- *     Returns %TRUE if the entry was unhooked, else %FALSE if it was
- *             previously unhooked.
- *     The caller must have a write lock on the parent directory.
- */
-
-static int _devfs_unhook(struct devfs_entry *de)
-{
-       struct devfs_entry *parent;
-
-       if (!de || (de->prev == de))
-               return FALSE;
-       parent = de->parent;
-       if (de->prev == NULL)
-               parent->u.dir.first = de->next;
-       else
-               de->prev->next = de->next;
-       if (de->next == NULL)
-               parent->u.dir.last = de->prev;
-       else
-               de->next->prev = de->prev;
-       de->prev = de;          /*  Indicate we're unhooked                      */
-       de->next = NULL;        /*  Force early termination for <devfs_readdir>  */
-       return TRUE;
-}                              /*  End Function _devfs_unhook  */
-
-/**
- *     _devfs_unregister - Unregister a device entry from its parent.
- *     @dir: The parent directory.
- *     @de: The entry to unregister.
- *
- *     The caller must have a write lock on the parent directory, which is
- *     unlocked by this function.
- */
-
-static void _devfs_unregister(struct devfs_entry *dir, struct devfs_entry *de)
-{
-       int unhooked = _devfs_unhook(de);
-
-       write_unlock(&dir->u.dir.lock);
-       if (!unhooked)
-               return;
-       devfs_get(dir);
-       devfsd_notify(de, DEVFSD_NOTIFY_UNREGISTERED);
-       free_dentry(de);
-       devfs_put(dir);
-       if (!S_ISDIR(de->mode))
-               return;
-       while (TRUE) {          /*  Recursively unregister: this is a stack chomper  */
-               struct devfs_entry *child;
-
-               write_lock(&de->u.dir.lock);
-               de->u.dir.no_more_additions = TRUE;
-               child = de->u.dir.first;
-               VERIFY_ENTRY(child);
-               _devfs_unregister(de, child);
-               if (!child)
-                       break;
-               DPRINTK(DEBUG_UNREGISTER, "(%s): child: %p  refcount: %d\n",
-                       child->name, child, atomic_read(&child->refcount));
-               devfs_put(child);
-       }
-}                              /*  End Function _devfs_unregister  */
-
-static int devfs_do_symlink(devfs_handle_t dir, const char *name,
-                           const char *link, devfs_handle_t * handle)
-{
-       int err;
-       unsigned int linklength;
-       char *newlink;
-       struct devfs_entry *de;
-
-       if (handle != NULL)
-               *handle = NULL;
-       if (name == NULL) {
-               PRINTK("(): NULL name pointer\n");
-               return -EINVAL;
-       }
-       if (link == NULL) {
-               PRINTK("(%s): NULL link pointer\n", name);
-               return -EINVAL;
-       }
-       linklength = strlen(link);
-       if ((newlink = kmalloc(linklength + 1, GFP_KERNEL)) == NULL)
-               return -ENOMEM;
-       memcpy(newlink, link, linklength);
-       newlink[linklength] = '\0';
-       if ((de = _devfs_prepare_leaf(&dir, name, S_IFLNK | S_IRUGO | S_IXUGO))
-           == NULL) {
-               PRINTK("(%s): could not prepare leaf\n", name);
-               kfree(newlink);
-               return -ENOTDIR;
-       }
-       de->info = NULL;
-       de->u.symlink.linkname = newlink;
-       de->u.symlink.length = linklength;
-       if ((err = _devfs_append_entry(dir, de, NULL)) != 0) {
-               PRINTK("(%s): could not append to parent, err: %d\n", name,
-                      err);
-               devfs_put(dir);
-               return err;
-       }
-       devfs_put(dir);
-#ifdef CONFIG_DEVFS_DEBUG
-       spin_lock(&stat_lock);
-       stat_num_bytes += linklength + 1;
-       spin_unlock(&stat_lock);
-#endif
-       if (handle != NULL)
-               *handle = de;
-       return 0;
-}                              /*  End Function devfs_do_symlink  */
-
-/**
- *     devfs_mk_symlink Create a symbolic link in the devfs namespace.
- *     @from: The name of the entry.
- *     @to: Name of the destination
- *
- *     Returns 0 on success, else a negative error code is returned.
- */
-
-int devfs_mk_symlink(const char *from, const char *to)
-{
-       devfs_handle_t de;
-       int err;
-
-       err = devfs_do_symlink(NULL, from, to, &de);
-       if (!err) {
-               de->vfs = TRUE;
-               devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);
-       }
-
-       return err;
-}
-
-/**
- *     devfs_mk_dir - Create a directory in the devfs namespace.
- *             new name is relative to the root of the devfs.
- *     @fmt: The name of the entry.
- *
- *     Use of this function is optional. The devfs_register() function
- *     will automatically create intermediate directories as needed. This function
- *     is provided for efficiency reasons, as it provides a handle to a directory.
- *     On failure %NULL is returned.
- */
-
-int devfs_mk_dir(const char *fmt, ...)
-{
-       struct devfs_entry *dir = NULL, *de = NULL, *old;
-       char buf[64];
-       va_list args;
-       int error, n;
-
-       va_start(args, fmt);
-       n = vsnprintf(buf, 64, fmt, args);
-       if (n >= 64 || !buf[0]) {
-               printk(KERN_WARNING "%s: invalid argument.", __FUNCTION__);
-               return -EINVAL;
-       }
-
-       de = _devfs_prepare_leaf(&dir, buf, MODE_DIR);
-       if (!de) {
-               PRINTK("(%s): could not prepare leaf\n", buf);
-               return -EINVAL;
-       }
-
-       error = _devfs_append_entry(dir, de, &old);
-       if (error == -EEXIST && S_ISDIR(old->mode)) {
-               /*
-                * devfs_mk_dir() of an already-existing directory will
-                * return success.
-                */
-               error = 0;
-               goto out_put;
-       } else if (error) {
-               PRINTK("(%s): could not append to dir: %p \"%s\"\n",
-                      buf, dir, dir->name);
-               devfs_put(old);
-               goto out_put;
-       }
-
-       devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);
-
-      out_put:
-       devfs_put(dir);
-       return error;
-}
-
-void devfs_remove(const char *fmt, ...)
-{
-       char buf[64];
-       va_list args;
-       int n;
-
-       va_start(args, fmt);
-       n = vsnprintf(buf, sizeof(buf), fmt, args);
-       if (n < sizeof(buf) && buf[0]) {
-               devfs_handle_t de = _devfs_find_entry(NULL, buf, 0);
-
-               if (!de) {
-                       printk(KERN_ERR "%s: %s not found, cannot remove\n",
-                              __FUNCTION__, buf);
-                       dump_stack();
-                       return;
-               }
-
-               write_lock(&de->parent->u.dir.lock);
-               _devfs_unregister(de->parent, de);
-               devfs_put(de);
-               devfs_put(de);
-       }
-}
-
-/**
- *     devfs_generate_path - Generate a pathname for an entry, relative to the devfs root.
- *     @de: The devfs entry.
- *     @path: The buffer to write the pathname to. The pathname and '\0'
- *             terminator will be written at the end of the buffer.
- *     @buflen: The length of the buffer.
- *
- *     Returns the offset in the buffer where the pathname starts on success,
- *     else a negative error code.
- */
-
-static int devfs_generate_path(devfs_handle_t de, char *path, int buflen)
-{
-       int pos;
-#define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name )
-
-       if (de == NULL)
-               return -EINVAL;
-       VERIFY_ENTRY(de);
-       if (de->namelen >= buflen)
-               return -ENAMETOOLONG;   /*  Must be first       */
-       path[buflen - 1] = '\0';
-       if (de->parent == NULL)
-               return buflen - 1;      /*  Don't prepend root  */
-       pos = buflen - de->namelen - 1;
-       memcpy(path + pos, NAMEOF(de), de->namelen);
-       for (de = de->parent; de->parent != NULL; de = de->parent) {
-               if (pos - de->namelen - 1 < 0)
-                       return -ENAMETOOLONG;
-               path[--pos] = '/';
-               pos -= de->namelen;
-               memcpy(path + pos, NAMEOF(de), de->namelen);
-       }
-       return pos;
-}                              /*  End Function devfs_generate_path  */
-
-/**
- *     devfs_setup - Process kernel boot options.
- *     @str: The boot options after the "devfs=".
- */
-
-static int __init devfs_setup(char *str)
-{
-       static struct {
-               char *name;
-               unsigned int mask;
-               unsigned int *opt;
-       } devfs_options_tab[] __initdata = {
-#ifdef CONFIG_DEVFS_DEBUG
-               {
-               "dall", DEBUG_ALL, &devfs_debug_init}, {
-               "dmod", DEBUG_MODULE_LOAD, &devfs_debug_init}, {
-               "dreg", DEBUG_REGISTER, &devfs_debug_init}, {
-               "dunreg", DEBUG_UNREGISTER, &devfs_debug_init}, {
-               "dfree", DEBUG_FREE, &devfs_debug_init}, {
-               "diget", DEBUG_I_GET, &devfs_debug_init}, {
-               "dchange", DEBUG_SET_FLAGS, &devfs_debug_init}, {
-               "dsread", DEBUG_S_READ, &devfs_debug_init}, {
-               "dichange", DEBUG_I_CHANGE, &devfs_debug_init}, {
-               "dimknod", DEBUG_I_MKNOD, &devfs_debug_init}, {
-               "dilookup", DEBUG_I_LOOKUP, &devfs_debug_init}, {
-               "diunlink", DEBUG_I_UNLINK, &devfs_debug_init},
-#endif                         /*  CONFIG_DEVFS_DEBUG  */
-               {
-               "mount", OPTION_MOUNT, &boot_options}, {
-               NULL, 0, NULL}
-       };
-
-       while ((*str != '\0') && !isspace(*str)) {
-               int i, found = 0, invert = 0;
-
-               if (strncmp(str, "no", 2) == 0) {
-                       invert = 1;
-                       str += 2;
-               }
-               for (i = 0; devfs_options_tab[i].name != NULL; i++) {
-                       int len = strlen(devfs_options_tab[i].name);
-
-                       if (strncmp(str, devfs_options_tab[i].name, len) == 0) {
-                               if (invert)
-                                       *devfs_options_tab[i].opt &=
-                                           ~devfs_options_tab[i].mask;
-                               else
-                                       *devfs_options_tab[i].opt |=
-                                           devfs_options_tab[i].mask;
-                               str += len;
-                               found = 1;
-                               break;
-                       }
-               }
-               if (!found)
-                       return 0;       /*  No match         */
-               if (*str != ',')
-                       return 0;       /*  No more options  */
-               ++str;
-       }
-       return 1;
-}                              /*  End Function devfs_setup  */
-
-__setup("devfs=", devfs_setup);
-
-EXPORT_SYMBOL(devfs_mk_dir);
-EXPORT_SYMBOL(devfs_remove);
-
-/**
- *     try_modload - Notify devfsd of an inode lookup by a non-devfsd process.
- *     @parent: The parent devfs entry.
- *     @fs_info: The filesystem info.
- *     @name: The device name.
- *     @namelen: The number of characters in @name.
- *     @buf: A working area that will be used. This must not go out of scope
- *            until devfsd is idle again.
- *
- *     Returns 0 on success (event was queued), else a negative error code.
- */
-
-static int try_modload(struct devfs_entry *parent, struct fs_info *fs_info,
-                      const char *name, unsigned namelen,
-                      struct devfs_entry *buf)
-{
-       if (!(fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP)))
-               return -ENOENT;
-       if (is_devfsd_or_child(fs_info))
-               return -ENOENT;
-       memset(buf, 0, sizeof *buf);
-       atomic_set(&buf->refcount, 1);
-       buf->parent = parent;
-       buf->namelen = namelen;
-       buf->u.name = name;
-       WRITE_ENTRY_MAGIC(buf, MAGIC_VALUE);
-       if (!devfsd_notify_de(buf, DEVFSD_NOTIFY_LOOKUP, 0,
-                             current->euid, current->egid, fs_info))
-               return -ENOENT;
-       /*  Possible success: event has been queued  */
-       return 0;
-}                              /*  End Function try_modload  */
-
-/*  Superblock operations follow  */
-
-static struct inode_operations devfs_iops;
-static struct inode_operations devfs_dir_iops;
-static const struct file_operations devfs_fops;
-static const struct file_operations devfs_dir_fops;
-static struct inode_operations devfs_symlink_iops;
-
-static int devfs_notify_change(struct dentry *dentry, struct iattr *iattr)
-{
-       int retval;
-       struct devfs_entry *de;
-       struct inode *inode = dentry->d_inode;
-       struct fs_info *fs_info = inode->i_sb->s_fs_info;
-
-       de = get_devfs_entry_from_vfs_inode(inode);
-       if (de == NULL)
-               return -ENODEV;
-       retval = inode_change_ok(inode, iattr);
-       if (retval != 0)
-               return retval;
-       retval = inode_setattr(inode, iattr);
-       if (retval != 0)
-               return retval;
-       DPRINTK(DEBUG_I_CHANGE, "(%d): VFS inode: %p  devfs_entry: %p\n",
-               (int)inode->i_ino, inode, de);
-       DPRINTK(DEBUG_I_CHANGE, "():   mode: 0%o  uid: %d  gid: %d\n",
-               (int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid);
-       /*  Inode is not on hash chains, thus must save permissions here rather
-          than in a write_inode() method  */
-       de->mode = inode->i_mode;
-       de->inode.uid = inode->i_uid;
-       de->inode.gid = inode->i_gid;
-       de->inode.atime = inode->i_atime;
-       de->inode.mtime = inode->i_mtime;
-       de->inode.ctime = inode->i_ctime;
-       if ((iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) &&
-           !is_devfsd_or_child(fs_info))
-               devfsd_notify_de(de, DEVFSD_NOTIFY_CHANGE, inode->i_mode,
-                                inode->i_uid, inode->i_gid, fs_info);
-       return 0;
-}                              /*  End Function devfs_notify_change  */
-
-static struct super_operations devfs_sops = {
-       .drop_inode = generic_delete_inode,
-       .statfs = simple_statfs,
-};
-
-/**
- *     _devfs_get_vfs_inode - Get a VFS inode.
- *     @sb: The super block.
- *     @de: The devfs inode.
- *     @dentry: The dentry to register with the devfs inode.
- *
- *     Returns the inode on success, else %NULL. An implicit devfs_get() is
- *       performed if the inode is created.
- */
-
-static struct inode *_devfs_get_vfs_inode(struct super_block *sb,
-                                         struct devfs_entry *de,
-                                         struct dentry *dentry)
-{
-       struct inode *inode;
-
-       if (de->prev == de)
-               return NULL;    /*  Quick check to see if unhooked  */
-       if ((inode = new_inode(sb)) == NULL) {
-               PRINTK("(%s): new_inode() failed, de: %p\n", de->name, de);
-               return NULL;
-       }
-       if (de->parent) {
-               read_lock(&de->parent->u.dir.lock);
-               if (de->prev != de)
-                       de->inode.dentry = dentry;      /*      Not unhooked  */
-               read_unlock(&de->parent->u.dir.lock);
-       } else
-               de->inode.dentry = dentry;      /*  Root: no locking needed  */
-       if (de->inode.dentry != dentry) {       /*  Must have been unhooked  */
-               iput(inode);
-               return NULL;
-       }
-       /* FIXME where is devfs_put? */
-       inode->u.generic_ip = devfs_get(de);
-       inode->i_ino = de->inode.ino;
-       DPRINTK(DEBUG_I_GET, "(%d): VFS inode: %p  devfs_entry: %p\n",
-               (int)inode->i_ino, inode, de);
-       inode->i_blocks = 0;
-       inode->i_blksize = FAKE_BLOCK_SIZE;
-       inode->i_op = &devfs_iops;
-       inode->i_mode = de->mode;
-       if (S_ISDIR(de->mode)) {
-               inode->i_op = &devfs_dir_iops;
-               inode->i_fop = &devfs_dir_fops;
-       } else if (S_ISLNK(de->mode)) {
-               inode->i_op = &devfs_symlink_iops;
-               inode->i_size = de->u.symlink.length;
-       } else if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) {
-               init_special_inode(inode, de->mode, de->u.dev);
-       } else if (S_ISFIFO(de->mode) || S_ISSOCK(de->mode)) {
-               init_special_inode(inode, de->mode, 0);
-       } else {
-               PRINTK("(%s): unknown mode %o de: %p\n",
-                      de->name, de->mode, de);
-               iput(inode);
-               devfs_put(de);
-               return NULL;
-       }
-
-       inode->i_uid = de->inode.uid;
-       inode->i_gid = de->inode.gid;
-       inode->i_atime = de->inode.atime;
-       inode->i_mtime = de->inode.mtime;
-       inode->i_ctime = de->inode.ctime;
-       DPRINTK(DEBUG_I_GET, "():   mode: 0%o  uid: %d  gid: %d\n",
-               (int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid);
-       return inode;
-}                              /*  End Function _devfs_get_vfs_inode  */
-
-/*  File operations for device entries follow  */
-
-static int devfs_readdir(struct file *file, void *dirent, filldir_t filldir)
-{
-       int err, count;
-       int stored = 0;
-       struct fs_info *fs_info;
-       struct devfs_entry *parent, *de, *next = NULL;
-       struct inode *inode = file->f_dentry->d_inode;
-
-       fs_info = inode->i_sb->s_fs_info;
-       parent = get_devfs_entry_from_vfs_inode(file->f_dentry->d_inode);
-       if ((long)file->f_pos < 0)
-               return -EINVAL;
-       DPRINTK(DEBUG_F_READDIR, "(%s): fs_info: %p  pos: %ld\n",
-               parent->name, fs_info, (long)file->f_pos);
-       switch ((long)file->f_pos) {
-       case 0:
-               err = (*filldir) (dirent, "..", 2, file->f_pos,
-                                 parent_ino(file->f_dentry), DT_DIR);
-               if (err == -EINVAL)
-                       break;
-               if (err < 0)
-                       return err;
-               file->f_pos++;
-               ++stored;
-               /*  Fall through  */
-       case 1:
-               err =
-                   (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino,
-                               DT_DIR);
-               if (err == -EINVAL)
-                       break;
-               if (err < 0)
-                       return err;
-               file->f_pos++;
-               ++stored;
-               /*  Fall through  */
-       default:
-               /*  Skip entries  */
-               count = file->f_pos - 2;
-               read_lock(&parent->u.dir.lock);
-               for (de = parent->u.dir.first; de && (count > 0); de = de->next)
-                       --count;
-               devfs_get(de);
-               read_unlock(&parent->u.dir.lock);
-               /*  Now add all remaining entries  */
-               while (de) {
-                       err = (*filldir) (dirent, de->name, de->namelen,
-                                         file->f_pos, de->inode.ino,
-                                         de->mode >> 12);
-                       if (err < 0)
-                               devfs_put(de);
-                       else {
-                               file->f_pos++;
-                               ++stored;
-                       }
-                       if (err == -EINVAL)
-                               break;
-                       if (err < 0)
-                               return err;
-                       read_lock(&parent->u.dir.lock);
-                       next = devfs_get(de->next);
-                       read_unlock(&parent->u.dir.lock);
-                       devfs_put(de);
-                       de = next;
-               }
-               break;
-       }
-       return stored;
-}                              /*  End Function devfs_readdir  */
-
-/* Open devfs specific special files */
-static int devfs_open(struct inode *inode, struct file *file)
-{
-       int err;
-       int minor = MINOR(inode->i_rdev);
-       struct file_operations *old_fops, *new_fops;
-
-       switch (minor) {
-       case 0:         /* /dev/.devfsd */
-               new_fops = fops_get(&devfsd_fops);
-               break;
-#ifdef CONFIG_DEVFS_DEBUG
-       case 1:         /* /dev/.stat */
-               new_fops = fops_get(&stat_fops);
-               break;
-#endif
-       default:
-               return -ENODEV;
-       }
-
-       if (new_fops == NULL)
-               return -ENODEV;
-       old_fops = file->f_op;
-       file->f_op = new_fops;
-       err = new_fops->open ? new_fops->open(inode, file) : 0;
-       if (err) {
-               file->f_op = old_fops;
-               fops_put(new_fops);
-       } else
-               fops_put(old_fops);
-       return err;
-}                              /*  End Function devfs_open  */
-
-static const struct file_operations devfs_fops = {
-       .open = devfs_open,
-};
-
-static const struct file_operations devfs_dir_fops = {
-       .read = generic_read_dir,
-       .readdir = devfs_readdir,
-};
-
-/*  Dentry operations for device entries follow  */
-
-/**
- *     devfs_d_release - Callback for when a dentry is freed.
- *     @dentry: The dentry.
- */
-
-static void devfs_d_release(struct dentry *dentry)
-{
-       DPRINTK(DEBUG_D_RELEASE, "(%p): inode: %p\n", dentry, dentry->d_inode);
-}                              /*  End Function devfs_d_release  */
-
-/**
- *     devfs_d_iput - Callback for when a dentry loses its inode.
- *     @dentry: The dentry.
- *     @inode: The inode.
- */
-
-static void devfs_d_iput(struct dentry *dentry, struct inode *inode)
-{
-       struct devfs_entry *de;
-
-       de = get_devfs_entry_from_vfs_inode(inode);
-       DPRINTK(DEBUG_D_IPUT,
-               "(%s): dentry: %p inode: %p de: %p de->dentry: %p\n", de->name,
-               dentry, inode, de, de->inode.dentry);
-       if (de->inode.dentry && (de->inode.dentry != dentry))
-               OOPS("(%s): de: %p dentry: %p de->dentry: %p\n",
-                    de->name, de, dentry, de->inode.dentry);
-       de->inode.dentry = NULL;
-       iput(inode);
-       devfs_put(de);
-}                              /*  End Function devfs_d_iput  */
-
-static int devfs_d_delete(struct dentry *dentry);
-
-static struct dentry_operations devfs_dops = {
-       .d_delete = devfs_d_delete,
-       .d_release = devfs_d_release,
-       .d_iput = devfs_d_iput,
-};
-
-static int devfs_d_revalidate_wait(struct dentry *dentry, struct nameidata *);
-
-static struct dentry_operations devfs_wait_dops = {
-       .d_delete = devfs_d_delete,
-       .d_release = devfs_d_release,
-       .d_iput = devfs_d_iput,
-       .d_revalidate = devfs_d_revalidate_wait,
-};
-
-/**
- *     devfs_d_delete - Callback for when all files for a dentry are closed.
- *     @dentry: The dentry.
- */
-
-static int devfs_d_delete(struct dentry *dentry)
-{
-       struct inode *inode = dentry->d_inode;
-
-       if (dentry->d_op == &devfs_wait_dops)
-               dentry->d_op = &devfs_dops;
-       /*  Unhash dentry if negative (has no inode)  */
-       if (inode == NULL) {
-               DPRINTK(DEBUG_D_DELETE, "(%p): dropping negative dentry\n",
-                       dentry);
-               return 1;
-       }
-       return 0;
-}                              /*  End Function devfs_d_delete  */
-
-struct devfs_lookup_struct {
-       devfs_handle_t de;
-       wait_queue_head_t wait_queue;
-};
-
-/* XXX: this doesn't handle the case where we got a negative dentry
-        but a devfs entry has been registered in the meanwhile */
-static int devfs_d_revalidate_wait(struct dentry *dentry, struct nameidata *nd)
-{
-       struct inode *dir = dentry->d_parent->d_inode;
-       struct fs_info *fs_info = dir->i_sb->s_fs_info;
-       devfs_handle_t parent = get_devfs_entry_from_vfs_inode(dir);
-       struct devfs_lookup_struct *lookup_info = dentry->d_fsdata;
-       DECLARE_WAITQUEUE(wait, current);
-       int need_lock;
-
-       /*
-        * FIXME HACK
-        *
-        * make sure that
-        *   d_instantiate always runs under lock
-        *   we release i_mutex lock before going to sleep
-        *
-        * unfortunately sometimes d_revalidate is called with
-        * and sometimes without i_mutex lock held. The following checks
-        * attempt to deduce when we need to add (and drop resp.) lock
-        * here. This relies on current (2.6.2) calling coventions:
-        *
-        *   lookup_hash is always run under i_mutex and is passing NULL
-        *   as nd
-        *
-        *   open(...,O_CREATE,...) calls _lookup_hash under i_mutex
-        *   and sets flags to LOOKUP_OPEN|LOOKUP_CREATE
-        *
-        *   all other invocations of ->d_revalidate seem to happen
-        *   outside of i_mutex
-        */
-       need_lock = nd &&
-           (!(nd->flags & LOOKUP_CREATE) || (nd->flags & LOOKUP_PARENT));
-
-       if (need_lock)
-               mutex_lock(&dir->i_mutex);
-
-       if (is_devfsd_or_child(fs_info)) {
-               devfs_handle_t de = lookup_info->de;
-               struct inode *inode;
-
-               DPRINTK(DEBUG_I_LOOKUP,
-                       "(%s): dentry: %p inode: %p de: %p by: \"%s\"\n",
-                       dentry->d_name.name, dentry, dentry->d_inode, de,
-                       current->comm);
-               if (dentry->d_inode)
-                       goto out;
-               if (de == NULL) {
-                       read_lock(&parent->u.dir.lock);
-                       de = _devfs_search_dir(parent, dentry->d_name.name,
-                                              dentry->d_name.len);
-                       read_unlock(&parent->u.dir.lock);
-                       if (de == NULL)
-                               goto out;
-                       lookup_info->de = de;
-               }
-               /*  Create an inode, now that the driver information is available  */
-               inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry);
-               if (!inode)
-                       goto out;
-               DPRINTK(DEBUG_I_LOOKUP,
-                       "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
-                       de->name, de->inode.ino, inode, de, current->comm);
-               d_instantiate(dentry, inode);
-               goto out;
-       }
-       if (lookup_info == NULL)
-               goto out;       /*  Early termination  */
-       read_lock(&parent->u.dir.lock);
-       if (dentry->d_fsdata) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               add_wait_queue(&lookup_info->wait_queue, &wait);
-               read_unlock(&parent->u.dir.lock);
-               /* at this point it is always (hopefully) locked */
-               mutex_unlock(&dir->i_mutex);
-               schedule();
-               mutex_lock(&dir->i_mutex);
-               /*
-                * This does not need nor should remove wait from wait_queue.
-                * Wait queue head is never reused - nothing is ever added to it
-                * after all waiters have been waked up and head itself disappears
-                * very soon after it. Moreover it is local variable on stack that
-                * is likely to have already disappeared so any reference to it
-                * at this point is buggy.
-                */
-
-       } else
-               read_unlock(&parent->u.dir.lock);
-
-      out:
-       if (need_lock)
-               mutex_unlock(&dir->i_mutex);
-       return 1;
-}                              /*  End Function devfs_d_revalidate_wait  */
-
-/*  Inode operations for device entries follow  */
-
-static struct dentry *devfs_lookup(struct inode *dir, struct dentry *dentry,
-                                  struct nameidata *nd)
-{
-       struct devfs_entry tmp; /*  Must stay in scope until devfsd idle again  */
-       struct devfs_lookup_struct lookup_info;
-       struct fs_info *fs_info = dir->i_sb->s_fs_info;
-       struct devfs_entry *parent, *de;
-       struct inode *inode;
-       struct dentry *retval = NULL;
-
-       /*  Set up the dentry operations before anything else, to ensure cleaning
-          up on any error  */
-       dentry->d_op = &devfs_dops;
-       /*  First try to get the devfs entry for this directory  */
-       parent = get_devfs_entry_from_vfs_inode(dir);
-       DPRINTK(DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n",
-               dentry->d_name.name, dentry, parent, current->comm);
-       if (parent == NULL)
-               return ERR_PTR(-ENOENT);
-       read_lock(&parent->u.dir.lock);
-       de = _devfs_search_dir(parent, dentry->d_name.name, dentry->d_name.len);
-       read_unlock(&parent->u.dir.lock);
-       lookup_info.de = de;
-       init_waitqueue_head(&lookup_info.wait_queue);
-       dentry->d_fsdata = &lookup_info;
-       if (de == NULL) {       /*  Try with devfsd. For any kind of failure, leave a negative dentry
-                                  so someone else can deal with it (in the case where the sysadmin
-                                  does a mknod()). It's important to do this before hashing the
-                                  dentry, so that the devfsd queue is filled before revalidates
-                                  can start  */
-               if (try_modload(parent, fs_info, dentry->d_name.name, dentry->d_name.len, &tmp) < 0) {  /*  Lookup event was not queued to devfsd  */
-                       d_add(dentry, NULL);
-                       return NULL;
-               }
-       }
-       dentry->d_op = &devfs_wait_dops;
-       d_add(dentry, NULL);    /*  Open the floodgates  */
-       /*  Unlock directory semaphore, which will release any waiters. They
-          will get the hashed dentry, and may be forced to wait for
-          revalidation  */
-       mutex_unlock(&dir->i_mutex);
-       wait_for_devfsd_finished(fs_info);      /*  If I'm not devfsd, must wait  */
-       mutex_lock(&dir->i_mutex);      /*  Grab it again because them's the rules  */
-       de = lookup_info.de;
-       /*  If someone else has been so kind as to make the inode, we go home
-          early  */
-       if (dentry->d_inode)
-               goto out;
-       if (de == NULL) {
-               read_lock(&parent->u.dir.lock);
-               de = _devfs_search_dir(parent, dentry->d_name.name,
-                                      dentry->d_name.len);
-               read_unlock(&parent->u.dir.lock);
-               if (de == NULL)
-                       goto out;
-               /*  OK, there's an entry now, but no VFS inode yet  */
-       }
-       /*  Create an inode, now that the driver information is available  */
-       inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry);
-       if (!inode) {
-               retval = ERR_PTR(-ENOMEM);
-               goto out;
-       }
-       DPRINTK(DEBUG_I_LOOKUP,
-               "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n", de->name,
-               de->inode.ino, inode, de, current->comm);
-       d_instantiate(dentry, inode);
-      out:
-       write_lock(&parent->u.dir.lock);
-       dentry->d_op = &devfs_dops;
-       dentry->d_fsdata = NULL;
-       wake_up(&lookup_info.wait_queue);
-       write_unlock(&parent->u.dir.lock);
-       devfs_put(de);
-       return retval;
-}                              /*  End Function devfs_lookup  */
-
-static int devfs_unlink(struct inode *dir, struct dentry *dentry)
-{
-       int unhooked;
-       struct devfs_entry *de;
-       struct inode *inode = dentry->d_inode;
-       struct fs_info *fs_info = dir->i_sb->s_fs_info;
-
-       de = get_devfs_entry_from_vfs_inode(inode);
-       DPRINTK(DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
-       if (de == NULL)
-               return -ENOENT;
-       if (!de->vfs)
-               return -EPERM;
-       write_lock(&de->parent->u.dir.lock);
-       unhooked = _devfs_unhook(de);
-       write_unlock(&de->parent->u.dir.lock);
-       if (!unhooked)
-               return -ENOENT;
-       if (!is_devfsd_or_child(fs_info))
-               devfsd_notify_de(de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
-                                inode->i_uid, inode->i_gid, fs_info);
-       free_dentry(de);
-       devfs_put(de);
-       return 0;
-}                              /*  End Function devfs_unlink  */
-
-static int devfs_symlink(struct inode *dir, struct dentry *dentry,
-                        const char *symname)
-{
-       int err;
-       struct fs_info *fs_info = dir->i_sb->s_fs_info;
-       struct devfs_entry *parent, *de;
-       struct inode *inode;
-
-       /*  First try to get the devfs entry for this directory  */
-       parent = get_devfs_entry_from_vfs_inode(dir);
-       if (parent == NULL)
-               return -ENOENT;
-       err = devfs_do_symlink(parent, dentry->d_name.name, symname, &de);
-       DPRINTK(DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n",
-               dentry->d_name.name, err);
-       if (err < 0)
-               return err;
-       de->vfs = TRUE;
-       de->inode.uid = current->euid;
-       de->inode.gid = current->egid;
-       de->inode.atime = CURRENT_TIME;
-       de->inode.mtime = CURRENT_TIME;
-       de->inode.ctime = CURRENT_TIME;
-       if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL)
-               return -ENOMEM;
-       DPRINTK(DEBUG_DISABLED, "(%s): new VFS inode(%u): %p  dentry: %p\n",
-               dentry->d_name.name, de->inode.ino, inode, dentry);
-       d_instantiate(dentry, inode);
-       if (!is_devfsd_or_child(fs_info))
-               devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-                                inode->i_uid, inode->i_gid, fs_info);
-       return 0;
-}                              /*  End Function devfs_symlink  */
-
-static int devfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
-{
-       int err;
-       struct fs_info *fs_info = dir->i_sb->s_fs_info;
-       struct devfs_entry *parent, *de;
-       struct inode *inode;
-
-       mode = (mode & ~S_IFMT) | S_IFDIR;      /*  VFS doesn't pass S_IFMT part  */
-       parent = get_devfs_entry_from_vfs_inode(dir);
-       if (parent == NULL)
-               return -ENOENT;
-       de = _devfs_alloc_entry(dentry->d_name.name, dentry->d_name.len, mode);
-       if (!de)
-               return -ENOMEM;
-       de->vfs = TRUE;
-       if ((err = _devfs_append_entry(parent, de, NULL)) != 0)
-               return err;
-       de->inode.uid = current->euid;
-       de->inode.gid = current->egid;
-       de->inode.atime = CURRENT_TIME;
-       de->inode.mtime = CURRENT_TIME;
-       de->inode.ctime = CURRENT_TIME;
-       if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL)
-               return -ENOMEM;
-       DPRINTK(DEBUG_DISABLED, "(%s): new VFS inode(%u): %p  dentry: %p\n",
-               dentry->d_name.name, de->inode.ino, inode, dentry);
-       d_instantiate(dentry, inode);
-       if (!is_devfsd_or_child(fs_info))
-               devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-                                inode->i_uid, inode->i_gid, fs_info);
-       return 0;
-}                              /*  End Function devfs_mkdir  */
-
-static int devfs_rmdir(struct inode *dir, struct dentry *dentry)
-{
-       int err = 0;
-       struct devfs_entry *de;
-       struct fs_info *fs_info = dir->i_sb->s_fs_info;
-       struct inode *inode = dentry->d_inode;
-
-       if (dir->i_sb->s_fs_info != inode->i_sb->s_fs_info)
-               return -EINVAL;
-       de = get_devfs_entry_from_vfs_inode(inode);
-       if (de == NULL)
-               return -ENOENT;
-       if (!S_ISDIR(de->mode))
-               return -ENOTDIR;
-       if (!de->vfs)
-               return -EPERM;
-       /*  First ensure the directory is empty and will stay that way  */
-       write_lock(&de->u.dir.lock);
-       if (de->u.dir.first)
-               err = -ENOTEMPTY;
-       else
-               de->u.dir.no_more_additions = TRUE;
-       write_unlock(&de->u.dir.lock);
-       if (err)
-               return err;
-       /*  Now unhook the directory from its parent  */
-       write_lock(&de->parent->u.dir.lock);
-       if (!_devfs_unhook(de))
-               err = -ENOENT;
-       write_unlock(&de->parent->u.dir.lock);
-       if (err)
-               return err;
-       if (!is_devfsd_or_child(fs_info))
-               devfsd_notify_de(de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
-                                inode->i_uid, inode->i_gid, fs_info);
-       free_dentry(de);
-       devfs_put(de);
-       return 0;
-}                              /*  End Function devfs_rmdir  */
-
-static int devfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
-                      dev_t rdev)
-{
-       int err;
-       struct fs_info *fs_info = dir->i_sb->s_fs_info;
-       struct devfs_entry *parent, *de;
-       struct inode *inode;
-
-       DPRINTK(DEBUG_I_MKNOD, "(%s): mode: 0%o  dev: %u:%u\n",
-               dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
-       parent = get_devfs_entry_from_vfs_inode(dir);
-       if (parent == NULL)
-               return -ENOENT;
-       de = _devfs_alloc_entry(dentry->d_name.name, dentry->d_name.len, mode);
-       if (!de)
-               return -ENOMEM;
-       de->vfs = TRUE;
-       if (S_ISCHR(mode) || S_ISBLK(mode))
-               de->u.dev = rdev;
-       if ((err = _devfs_append_entry(parent, de, NULL)) != 0)
-               return err;
-       de->inode.uid = current->euid;
-       de->inode.gid = current->egid;
-       de->inode.atime = CURRENT_TIME;
-       de->inode.mtime = CURRENT_TIME;
-       de->inode.ctime = CURRENT_TIME;
-       if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL)
-               return -ENOMEM;
-       DPRINTK(DEBUG_I_MKNOD, ":   new VFS inode(%u): %p  dentry: %p\n",
-               de->inode.ino, inode, dentry);
-       d_instantiate(dentry, inode);
-       if (!is_devfsd_or_child(fs_info))
-               devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-                                inode->i_uid, inode->i_gid, fs_info);
-       return 0;
-}                              /*  End Function devfs_mknod  */
-
-static void *devfs_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
-       struct devfs_entry *p = get_devfs_entry_from_vfs_inode(dentry->d_inode);
-       nd_set_link(nd, p ? p->u.symlink.linkname : ERR_PTR(-ENODEV));
-       return NULL;
-}                              /*  End Function devfs_follow_link  */
-
-static struct inode_operations devfs_iops = {
-       .setattr = devfs_notify_change,
-};
-
-static struct inode_operations devfs_dir_iops = {
-       .lookup = devfs_lookup,
-       .unlink = devfs_unlink,
-       .symlink = devfs_symlink,
-       .mkdir = devfs_mkdir,
-       .rmdir = devfs_rmdir,
-       .mknod = devfs_mknod,
-       .setattr = devfs_notify_change,
-};
-
-static struct inode_operations devfs_symlink_iops = {
-       .readlink = generic_readlink,
-       .follow_link = devfs_follow_link,
-       .setattr = devfs_notify_change,
-};
-
-static int devfs_fill_super(struct super_block *sb, void *data, int silent)
-{
-       struct inode *root_inode = NULL;
-
-       if (_devfs_get_root_entry() == NULL)
-               goto out_no_root;
-       atomic_set(&fs_info.devfsd_overrun_count, 0);
-       init_waitqueue_head(&fs_info.devfsd_wait_queue);
-       init_waitqueue_head(&fs_info.revalidate_wait_queue);
-       fs_info.sb = sb;
-       sb->s_fs_info = &fs_info;
-       sb->s_blocksize = 1024;
-       sb->s_blocksize_bits = 10;
-       sb->s_magic = DEVFS_SUPER_MAGIC;
-       sb->s_op = &devfs_sops;
-       sb->s_time_gran = 1;
-       if ((root_inode = _devfs_get_vfs_inode(sb, root_entry, NULL)) == NULL)
-               goto out_no_root;
-       sb->s_root = d_alloc_root(root_inode);
-       if (!sb->s_root)
-               goto out_no_root;
-       DPRINTK(DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->s_fs_info);
-       return 0;
-
-      out_no_root:
-       PRINTK("(): get root inode failed\n");
-       if (root_inode)
-               iput(root_inode);
-       return -EINVAL;
-}                              /*  End Function devfs_fill_super  */
-
-static int devfs_get_sb(struct file_system_type *fs_type,
-                       int flags, const char *dev_name,
-                       void *data, struct vfsmount *mnt)
-{
-       return get_sb_single(fs_type, flags, data, devfs_fill_super, mnt);
-}
-
-static struct file_system_type devfs_fs_type = {
-       .name = DEVFS_NAME,
-       .get_sb = devfs_get_sb,
-       .kill_sb = kill_anon_super,
-};
-
-/*  File operations for devfsd follow  */
-
-static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len,
-                          loff_t * ppos)
-{
-       int done = FALSE;
-       int ival;
-       loff_t pos, devname_offset, tlen, rpos;
-       devfs_handle_t de;
-       struct devfsd_buf_entry *entry;
-       struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->s_fs_info;
-       struct devfsd_notify_struct *info = fs_info->devfsd_info;
-       DECLARE_WAITQUEUE(wait, current);
-
-       /*  Verify the task has grabbed the queue  */
-       if (fs_info->devfsd_task != current)
-               return -EPERM;
-       info->major = 0;
-       info->minor = 0;
-       /*  Block for a new entry  */
-       set_current_state(TASK_INTERRUPTIBLE);
-       add_wait_queue(&fs_info->devfsd_wait_queue, &wait);
-       while (devfsd_queue_empty(fs_info)) {
-               fs_info->devfsd_sleeping = TRUE;
-               wake_up(&fs_info->revalidate_wait_queue);
-               schedule();
-               fs_info->devfsd_sleeping = FALSE;
-               if (signal_pending(current)) {
-                       remove_wait_queue(&fs_info->devfsd_wait_queue, &wait);
-                       __set_current_state(TASK_RUNNING);
-                       return -EINTR;
-               }
-               set_current_state(TASK_INTERRUPTIBLE);
-       }
-       remove_wait_queue(&fs_info->devfsd_wait_queue, &wait);
-       __set_current_state(TASK_RUNNING);
-       /*  Now play with the data  */
-       ival = atomic_read(&fs_info->devfsd_overrun_count);
-       info->overrun_count = ival;
-       entry = fs_info->devfsd_first_event;
-       info->type = entry->type;
-       info->mode = entry->mode;
-       info->uid = entry->uid;
-       info->gid = entry->gid;
-       de = entry->de;
-       if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) {
-               info->major = MAJOR(de->u.dev);
-               info->minor = MINOR(de->u.dev);
-       }
-       pos = devfs_generate_path(de, info->devname, DEVFS_PATHLEN);
-       if (pos < 0)
-               return pos;
-       info->namelen = DEVFS_PATHLEN - pos - 1;
-       if (info->mode == 0)
-               info->mode = de->mode;
-       devname_offset = info->devname - (char *)info;
-       rpos = *ppos;
-       if (rpos < devname_offset) {
-               /*  Copy parts of the header  */
-               tlen = devname_offset - rpos;
-               if (tlen > len)
-                       tlen = len;
-               if (copy_to_user(buf, (char *)info + rpos, tlen)) {
-                       return -EFAULT;
-               }
-               rpos += tlen;
-               buf += tlen;
-               len -= tlen;
-       }
-       if ((rpos >= devname_offset) && (len > 0)) {
-               /*  Copy the name  */
-               tlen = info->namelen + 1;
-               if (tlen > len)
-                       tlen = len;
-               else
-                       done = TRUE;
-               if (copy_to_user
-                   (buf, info->devname + pos + rpos - devname_offset, tlen)) {
-                       return -EFAULT;
-               }
-               rpos += tlen;
-       }
-       tlen = rpos - *ppos;
-       if (done) {
-               devfs_handle_t parent;
-
-               spin_lock(&fs_info->devfsd_buffer_lock);
-               fs_info->devfsd_first_event = entry->next;
-               if (entry->next == NULL)
-                       fs_info->devfsd_last_event = NULL;
-               spin_unlock(&fs_info->devfsd_buffer_lock);
-               for (; de != NULL; de = parent) {
-                       parent = de->parent;
-                       devfs_put(de);
-               }
-               kmem_cache_free(devfsd_buf_cache, entry);
-               if (ival > 0)
-                       atomic_sub(ival, &fs_info->devfsd_overrun_count);
-               *ppos = 0;
-       } else
-               *ppos = rpos;
-       return tlen;
-}                              /*  End Function devfsd_read  */
-
-static int devfsd_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg)
-{
-       int ival;
-       struct fs_info *fs_info = inode->i_sb->s_fs_info;
-
-       switch (cmd) {
-       case DEVFSDIOC_GET_PROTO_REV:
-               ival = DEVFSD_PROTOCOL_REVISION_KERNEL;
-               if (copy_to_user((void __user *)arg, &ival, sizeof ival))
-                       return -EFAULT;
-               break;
-       case DEVFSDIOC_SET_EVENT_MASK:
-               /*  Ensure only one reader has access to the queue. This scheme will
-                  work even if the global kernel lock were to be removed, because it
-                  doesn't matter who gets in first, as long as only one gets it  */
-               if (fs_info->devfsd_task == NULL) {
-                       static DEFINE_SPINLOCK(lock);
-
-                       if (!spin_trylock(&lock))
-                               return -EBUSY;
-                       if (fs_info->devfsd_task != NULL) {     /*  We lost the race...  */
-                               spin_unlock(&lock);
-                               return -EBUSY;
-                       }
-                       fs_info->devfsd_task = current;
-                       spin_unlock(&lock);
-                       fs_info->devfsd_pgrp =
-                           (process_group(current) ==
-                            current->pid) ? process_group(current) : 0;
-                       fs_info->devfsd_file = file;
-                       fs_info->devfsd_info =
-                           kmalloc(sizeof *fs_info->devfsd_info, GFP_KERNEL);
-                       if (!fs_info->devfsd_info) {
-                               devfsd_close(inode, file);
-                               return -ENOMEM;
-                       }
-               } else if (fs_info->devfsd_task != current)
-                       return -EBUSY;
-               fs_info->devfsd_event_mask = arg;       /*  Let the masses come forth  */
-               break;
-       case DEVFSDIOC_RELEASE_EVENT_QUEUE:
-               if (fs_info->devfsd_file != file)
-                       return -EPERM;
-               return devfsd_close(inode, file);
-               /*break; */
-#ifdef CONFIG_DEVFS_DEBUG
-       case DEVFSDIOC_SET_DEBUG_MASK:
-               if (copy_from_user(&ival, (void __user *)arg, sizeof ival))
-                       return -EFAULT;
-               devfs_debug = ival;
-               break;
-#endif
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}                              /*  End Function devfsd_ioctl  */
-
-static int devfsd_close(struct inode *inode, struct file *file)
-{
-       struct devfsd_buf_entry *entry, *next;
-       struct fs_info *fs_info = inode->i_sb->s_fs_info;
-
-       if (fs_info->devfsd_file != file)
-               return 0;
-       fs_info->devfsd_event_mask = 0;
-       fs_info->devfsd_file = NULL;
-       spin_lock(&fs_info->devfsd_buffer_lock);
-       entry = fs_info->devfsd_first_event;
-       fs_info->devfsd_first_event = NULL;
-       fs_info->devfsd_last_event = NULL;
-       kfree(fs_info->devfsd_info);
-       fs_info->devfsd_info = NULL;
-       spin_unlock(&fs_info->devfsd_buffer_lock);
-       fs_info->devfsd_pgrp = 0;
-       fs_info->devfsd_task = NULL;
-       wake_up(&fs_info->revalidate_wait_queue);
-       for (; entry; entry = next) {
-               next = entry->next;
-               kmem_cache_free(devfsd_buf_cache, entry);
-       }
-       return 0;
-}                              /*  End Function devfsd_close  */
-
-#ifdef CONFIG_DEVFS_DEBUG
-static ssize_t stat_read(struct file *file, char __user *buf, size_t len,
-                        loff_t * ppos)
-{
-       ssize_t num;
-       char txt[80];
-
-       num = sprintf(txt, "Number of entries: %u  number of bytes: %u\n",
-                     stat_num_entries, stat_num_bytes) + 1;
-       if (*ppos >= num)
-               return 0;
-       if (*ppos + len > num)
-               len = num - *ppos;
-       if (copy_to_user(buf, txt + *ppos, len))
-               return -EFAULT;
-       *ppos += len;
-       return len;
-}                              /*  End Function stat_read  */
-#endif
-
-static int __init init_devfs_fs(void)
-{
-       int err;
-       int major;
-       struct devfs_entry *devfsd;
-#ifdef CONFIG_DEVFS_DEBUG
-       struct devfs_entry *stat;
-#endif
-
-       if (_devfs_get_root_entry() == NULL)
-               return -ENOMEM;
-
-       printk(KERN_INFO "%s: %s Richard Gooch (rgooch@atnf.csiro.au)\n",
-              DEVFS_NAME, DEVFS_VERSION);
-       devfsd_buf_cache = kmem_cache_create("devfsd_event",
-                                            sizeof(struct devfsd_buf_entry),
-                                            0, 0, NULL, NULL);
-       if (!devfsd_buf_cache)
-               OOPS("(): unable to allocate event slab\n");
-#ifdef CONFIG_DEVFS_DEBUG
-       devfs_debug = devfs_debug_init;
-       printk(KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug);
-#endif
-       printk(KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options);
-
-       /* register special device for devfsd communication */
-       major = register_chrdev(0, "devfs", &devfs_fops);
-       if (major < 0)
-               return major;
-
-       /*  And create the entry for ".devfsd"  */
-       devfsd = _devfs_alloc_entry(".devfsd", 0, S_IFCHR | S_IRUSR | S_IWUSR);
-       if (devfsd == NULL)
-               return -ENOMEM;
-       devfsd->u.dev = MKDEV(major, 0);
-       _devfs_append_entry(root_entry, devfsd, NULL);
-
-#ifdef CONFIG_DEVFS_DEBUG
-       stat = _devfs_alloc_entry(".stat", 0, S_IFCHR | S_IRUGO);
-       if (stat == NULL)
-               return -ENOMEM;
-       stat->u.dev = MKDEV(major, 1);
-       _devfs_append_entry(root_entry, stat, NULL);
-#endif
-
-       err = register_filesystem(&devfs_fs_type);
-       return err;
-}                              /*  End Function init_devfs_fs  */
-
-void __init mount_devfs_fs(void)
-{
-       int err;
-
-       if (!(boot_options & OPTION_MOUNT))
-               return;
-       err = do_mount("none", "/dev", "devfs", 0, NULL);
-       if (err == 0)
-               printk(KERN_INFO "Mounted devfs on /dev\n");
-       else
-               PRINTK("(): unable to mount devfs, err: %d\n", err);
-}                              /*  End Function mount_devfs_fs  */
-
-module_init(init_devfs_fs)
diff --git a/fs/devfs/util.c b/fs/devfs/util.c
deleted file mode 100644 (file)
index db06d38..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*  devfs (Device FileSystem) utilities.
-
-    Copyright (C) 1999-2002  Richard Gooch
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 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
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
-    The postal address is:
-      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
-
-    ChangeLog
-
-    19991031   Richard Gooch <rgooch@atnf.csiro.au>
-               Created.
-    19991103   Richard Gooch <rgooch@atnf.csiro.au>
-               Created <_devfs_convert_name> and supported SCSI and IDE CD-ROMs
-    20000203   Richard Gooch <rgooch@atnf.csiro.au>
-               Changed operations pointer type to void *.
-    20000621   Richard Gooch <rgooch@atnf.csiro.au>
-               Changed interface to <devfs_register_series>.
-    20000622   Richard Gooch <rgooch@atnf.csiro.au>
-               Took account of interface change to <devfs_mk_symlink>.
-               Took account of interface change to <devfs_mk_dir>.
-    20010519   Richard Gooch <rgooch@atnf.csiro.au>
-               Documentation cleanup.
-    20010709   Richard Gooch <rgooch@atnf.csiro.au>
-               Created <devfs_*alloc_major> and <devfs_*alloc_devnum>.
-    20010710   Richard Gooch <rgooch@atnf.csiro.au>
-               Created <devfs_*alloc_unique_number>.
-    20010730   Richard Gooch <rgooch@atnf.csiro.au>
-               Documentation typo fix.
-    20010806   Richard Gooch <rgooch@atnf.csiro.au>
-               Made <block_semaphore> and <char_semaphore> private.
-    20010813   Richard Gooch <rgooch@atnf.csiro.au>
-               Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers
-    20010818   Richard Gooch <rgooch@atnf.csiro.au>
-               Updated major masks up to Linus' "no new majors" proclamation.
-              Block: were 126 now 122 free, char: were 26 now 19 free.
-    20020324   Richard Gooch <rgooch@atnf.csiro.au>
-               Fixed bug in <devfs_alloc_unique_number>: was clearing beyond
-              bitfield.
-    20020326   Richard Gooch <rgooch@atnf.csiro.au>
-               Fixed bitfield data type for <devfs_*alloc_devnum>.
-               Made major bitfield type and initialiser 64 bit safe.
-    20020413   Richard Gooch <rgooch@atnf.csiro.au>
-               Fixed shift warning on 64 bit machines.
-    20020428   Richard Gooch <rgooch@atnf.csiro.au>
-               Copied and used macro for error messages from fs/devfs/base.c 
-    20021013   Richard Gooch <rgooch@atnf.csiro.au>
-               Documentation fix.
-    20030101   Adam J. Richter <adam@yggdrasil.com>
-               Eliminate DEVFS_SPECIAL_{CHR,BLK}.  Use mode_t instead.
-    20030106   Christoph Hellwig <hch@infradead.org>
-               Rewrite devfs_{,de}alloc_devnum to look like C code.
-*/
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/genhd.h>
-#include <linux/bitops.h>
-
-int devfs_register_tape(const char *name)
-{
-       char tname[32], dest[64];
-       static unsigned int tape_counter;
-       unsigned int n = tape_counter++;
-
-       sprintf(dest, "../%s", name);
-       sprintf(tname, "tapes/tape%u", n);
-       devfs_mk_symlink(tname, dest);
-
-       return n;
-}
-
-EXPORT_SYMBOL(devfs_register_tape);
-
-void devfs_unregister_tape(int num)
-{
-       if (num >= 0)
-               devfs_remove("tapes/tape%u", num);
-}
-
-EXPORT_SYMBOL(devfs_unregister_tape);
index 180607f9314dc9368b2f90cbd4bac7d8542a4425..174696f9bf14eb5c803d9200b89da6e97b68b5f0 100644 (file)
@@ -21,7 +21,7 @@ static sector_t _efs_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,efs_get_block);
 }
-static struct address_space_operations efs_aops = {
+static const struct address_space_operations efs_aops = {
        .readpage = efs_readpage,
        .sync_page = block_sync_page,
        .bmap = _efs_bmap
index 3d9a350e3e7f6f8687726c7e962a55dbca39a3a8..e249cf733a6bdb9b728b664a9910dff59edb8101 100644 (file)
@@ -53,6 +53,6 @@ fail:
        return err;
 }
 
-struct address_space_operations efs_symlink_aops = {
+const struct address_space_operations efs_symlink_aops = {
        .readpage       = efs_symlink_readpage
 };
index 9f74a62be555f1cc84da03e9455d8efb27652a5e..e65a019fc7a58b87f80c64fcaa7944b06bd30242 100644 (file)
@@ -162,9 +162,9 @@ extern const struct file_operations ext2_file_operations;
 extern const struct file_operations ext2_xip_file_operations;
 
 /* inode.c */
-extern struct address_space_operations ext2_aops;
-extern struct address_space_operations ext2_aops_xip;
-extern struct address_space_operations ext2_nobh_aops;
+extern const struct address_space_operations ext2_aops;
+extern const struct address_space_operations ext2_aops_xip;
+extern const struct address_space_operations ext2_nobh_aops;
 
 /* namei.c */
 extern struct inode_operations ext2_dir_inode_operations;
index 04af9c45dce23a0f50df3bf735a8749c092c3a85..fb4d3220eb8d717918445b13d8f920023e3a13fb 100644 (file)
@@ -684,7 +684,7 @@ ext2_writepages(struct address_space *mapping, struct writeback_control *wbc)
        return mpage_writepages(mapping, wbc, ext2_get_block);
 }
 
-struct address_space_operations ext2_aops = {
+const struct address_space_operations ext2_aops = {
        .readpage               = ext2_readpage,
        .readpages              = ext2_readpages,
        .writepage              = ext2_writepage,
@@ -697,12 +697,12 @@ struct address_space_operations ext2_aops = {
        .migratepage            = buffer_migrate_page,
 };
 
-struct address_space_operations ext2_aops_xip = {
+const struct address_space_operations ext2_aops_xip = {
        .bmap                   = ext2_bmap,
        .get_xip_page           = ext2_get_xip_page,
 };
 
-struct address_space_operations ext2_nobh_aops = {
+const struct address_space_operations ext2_nobh_aops = {
        .readpage               = ext2_readpage,
        .readpages              = ext2_readpages,
        .writepage              = ext2_nobh_writepage,
index 0321e1b9034a9e71db80c43cc372402ef3371c8c..f804d5e9d60c6cc81cf35c33b42b4a8d9d2fc896 100644 (file)
@@ -1698,7 +1698,7 @@ static int ext3_journalled_set_page_dirty(struct page *page)
        return __set_page_dirty_nobuffers(page);
 }
 
-static struct address_space_operations ext3_ordered_aops = {
+static const struct address_space_operations ext3_ordered_aops = {
        .readpage       = ext3_readpage,
        .readpages      = ext3_readpages,
        .writepage      = ext3_ordered_writepage,
@@ -1712,7 +1712,7 @@ static struct address_space_operations ext3_ordered_aops = {
        .migratepage    = buffer_migrate_page,
 };
 
-static struct address_space_operations ext3_writeback_aops = {
+static const struct address_space_operations ext3_writeback_aops = {
        .readpage       = ext3_readpage,
        .readpages      = ext3_readpages,
        .writepage      = ext3_writeback_writepage,
@@ -1726,7 +1726,7 @@ static struct address_space_operations ext3_writeback_aops = {
        .migratepage    = buffer_migrate_page,
 };
 
-static struct address_space_operations ext3_journalled_aops = {
+static const struct address_space_operations ext3_journalled_aops = {
        .readpage       = ext3_readpage,
        .readpages      = ext3_readpages,
        .writepage      = ext3_journalled_writepage,
index 7c35d582ec104c080cc5e760178b9986588f1362..31b7174176ba76798284286e8f6767419cef7e12 100644 (file)
@@ -196,7 +196,7 @@ static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping, block, fat_get_block);
 }
 
-static struct address_space_operations fat_aops = {
+static const struct address_space_operations fat_aops = {
        .readpage       = fat_readpage,
        .readpages      = fat_readpages,
        .writepage      = fat_writepage,
index 6f5df1700e9506b230d973ec0b88b546bd98805b..4e25f3fbed86c71d7a92722ea00bfbb82711860f 100644 (file)
@@ -56,7 +56,7 @@ struct inode_operations vxfs_immed_symlink_iops = {
 /*
  * Adress space operations for immed files and directories.
  */
-struct address_space_operations vxfs_immed_aops = {
+const struct address_space_operations vxfs_immed_aops = {
        .readpage =             vxfs_immed_readpage,
 };
 
index f544aae9169fb86847a0794006dde0a73910291e..ca6a39714771e317a89ad31c48e08c541438206a 100644 (file)
@@ -41,8 +41,8 @@
 #include "vxfs_extern.h"
 
 
-extern struct address_space_operations vxfs_aops;
-extern struct address_space_operations vxfs_immed_aops;
+extern const struct address_space_operations vxfs_aops;
+extern const struct address_space_operations vxfs_immed_aops;
 
 extern struct inode_operations vxfs_immed_symlink_iops;
 
@@ -295,7 +295,7 @@ vxfs_read_inode(struct inode *ip)
 {
        struct super_block              *sbp = ip->i_sb;
        struct vxfs_inode_info          *vip;
-       struct address_space_operations *aops;
+       const struct address_space_operations   *aops;
        ino_t                           ino = ip->i_ino;
 
        if (!(vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist)))
index c1be118fc0670a079099909c824535b599bc7423..decac62efe570ce9f81e0522eeadcbb765da9566 100644 (file)
@@ -42,7 +42,7 @@
 static int             vxfs_readpage(struct file *, struct page *);
 static sector_t                vxfs_bmap(struct address_space *, sector_t);
 
-struct address_space_operations vxfs_aops = {
+const struct address_space_operations vxfs_aops = {
        .readpage =             vxfs_readpage,
        .bmap =                 vxfs_bmap,
        .sync_page =            block_sync_page,
index 28aa81eae2cc6ddee6a2c41c5dee99254ea90f75..63614ed16336d7dec7bd4902a9c43d582e48842e 100644 (file)
@@ -770,7 +770,7 @@ static const struct file_operations fuse_direct_io_file_operations = {
        /* no mmap and sendfile */
 };
 
-static struct address_space_operations fuse_file_aops  = {
+static const struct address_space_operations fuse_file_aops  = {
        .readpage       = fuse_readpage,
        .prepare_write  = fuse_prepare_write,
        .commit_write   = fuse_commit_write,
index 3ed8663a8db1ea792d14d0ab9ab6d0821d2521ce..735332dfd1b8a70283d1c02b0de09b3272b485d7 100644 (file)
@@ -182,8 +182,8 @@ extern void hfs_file_truncate(struct inode *);
 extern int hfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 /* inode.c */
-extern struct address_space_operations hfs_aops;
-extern struct address_space_operations hfs_btree_aops;
+extern const struct address_space_operations hfs_aops;
+extern const struct address_space_operations hfs_btree_aops;
 
 extern struct inode *hfs_new_inode(struct inode *, struct qstr *, int);
 extern void hfs_inode_write_fork(struct inode *, struct hfs_extent *, __be32 *, __be32 *);
index 2d4ced22201ba18d3b8e81eb5b1860d63011897b..315cf44a90b23e60a55910c484a71d661e64fbd2 100644 (file)
@@ -114,7 +114,7 @@ static int hfs_writepages(struct address_space *mapping,
        return mpage_writepages(mapping, wbc, hfs_get_block);
 }
 
-struct address_space_operations hfs_btree_aops = {
+const struct address_space_operations hfs_btree_aops = {
        .readpage       = hfs_readpage,
        .writepage      = hfs_writepage,
        .sync_page      = block_sync_page,
@@ -124,7 +124,7 @@ struct address_space_operations hfs_btree_aops = {
        .releasepage    = hfs_releasepage,
 };
 
-struct address_space_operations hfs_aops = {
+const struct address_space_operations hfs_aops = {
        .readpage       = hfs_readpage,
        .writepage      = hfs_writepage,
        .sync_page      = block_sync_page,
index 7ae393637a0ccc688dbfd38f674123d673081471..8a1ca5ef7ada1f26468d031ee0882d61e350ca36 100644 (file)
@@ -323,8 +323,8 @@ int hfsplus_file_extend(struct inode *);
 void hfsplus_file_truncate(struct inode *);
 
 /* inode.c */
-extern struct address_space_operations hfsplus_aops;
-extern struct address_space_operations hfsplus_btree_aops;
+extern const struct address_space_operations hfsplus_aops;
+extern const struct address_space_operations hfsplus_btree_aops;
 
 void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *);
 void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *);
index acf66dba3e01ddc5256469ef5183853128107ee6..924ecdef8091fa0323ae03e62417263cbc055330 100644 (file)
@@ -109,7 +109,7 @@ static int hfsplus_writepages(struct address_space *mapping,
        return mpage_writepages(mapping, wbc, hfsplus_get_block);
 }
 
-struct address_space_operations hfsplus_btree_aops = {
+const struct address_space_operations hfsplus_btree_aops = {
        .readpage       = hfsplus_readpage,
        .writepage      = hfsplus_writepage,
        .sync_page      = block_sync_page,
@@ -119,7 +119,7 @@ struct address_space_operations hfsplus_btree_aops = {
        .releasepage    = hfsplus_releasepage,
 };
 
-struct address_space_operations hfsplus_aops = {
+const struct address_space_operations hfsplus_aops = {
        .readpage       = hfsplus_readpage,
        .writepage      = hfsplus_writepage,
        .sync_page      = block_sync_page,
index 8e0d37743e7ce54f698e9839ebf142e0941abaff..b82e3d9c879021ae9882158aa8df2080c73f144e 100644 (file)
@@ -54,7 +54,7 @@ static int append = 0;
 
 static struct inode_operations hostfs_iops;
 static struct inode_operations hostfs_dir_iops;
-static struct address_space_operations hostfs_link_aops;
+static const struct address_space_operations hostfs_link_aops;
 
 #ifndef MODULE
 static int __init hostfs_args(char *options, int *add)
@@ -518,7 +518,7 @@ int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
        return(err);
 }
 
-static struct address_space_operations hostfs_aops = {
+static const struct address_space_operations hostfs_aops = {
        .writepage      = hostfs_writepage,
        .readpage       = hostfs_readpage,
        .set_page_dirty = __set_page_dirty_nobuffers,
@@ -935,7 +935,7 @@ int hostfs_link_readpage(struct file *file, struct page *page)
        return(err);
 }
 
-static struct address_space_operations hostfs_link_aops = {
+static const struct address_space_operations hostfs_link_aops = {
        .readpage       = hostfs_link_readpage,
 };
 
index d3b9fffe45a140bedc792f9022f4af7c8f7908ce..d9eb19b7b8aecef05ef1d49d0a12feca4b184755 100644 (file)
@@ -99,7 +99,7 @@ static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,hpfs_get_block);
 }
-struct address_space_operations hpfs_aops = {
+const struct address_space_operations hpfs_aops = {
        .readpage = hpfs_readpage,
        .writepage = hpfs_writepage,
        .sync_page = block_sync_page,
index 29b7a3e55173e8825ed63d8f899076e045641c75..f687d54ed4422469ff43086b8b030e0b06b88e00 100644 (file)
@@ -268,7 +268,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, char *, char *, int);
 int hpfs_file_fsync(struct file *, struct dentry *, int);
 extern const struct file_operations hpfs_file_ops;
 extern struct inode_operations hpfs_file_iops;
-extern struct address_space_operations hpfs_aops;
+extern const struct address_space_operations hpfs_aops;
 
 /* inode.c */
 
@@ -304,7 +304,7 @@ void hpfs_decide_conv(struct inode *, unsigned char *, unsigned);
 /* namei.c */
 
 extern struct inode_operations hpfs_dir_iops;
-extern struct address_space_operations hpfs_symlink_aops;
+extern const struct address_space_operations hpfs_symlink_aops;
 
 static inline struct hpfs_inode_info *hpfs_i(struct inode *inode)
 {
index a03abb12c610e7e535725b8c00901c928dd0626f..59e7dc182a0c760ff78631cf162313ff6b2f97d4 100644 (file)
@@ -538,7 +538,7 @@ fail:
        return err;
 }
 
-struct address_space_operations hpfs_symlink_aops = {
+const struct address_space_operations hpfs_symlink_aops = {
        .readpage       = hpfs_symlink_readpage
 };
        
index e6410d8edd0e4751a6ada441c5a8f469dcd0fd29..6449cb697967d28818016b9ee4fbbc7519202203 100644 (file)
@@ -34,7 +34,7 @@
 #define HUGETLBFS_MAGIC        0x958458f6
 
 static struct super_operations hugetlbfs_ops;
-static struct address_space_operations hugetlbfs_aops;
+static const struct address_space_operations hugetlbfs_aops;
 const struct file_operations hugetlbfs_file_operations;
 static struct inode_operations hugetlbfs_dir_inode_operations;
 static struct inode_operations hugetlbfs_inode_operations;
@@ -547,7 +547,7 @@ static void hugetlbfs_destroy_inode(struct inode *inode)
        kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode));
 }
 
-static struct address_space_operations hugetlbfs_aops = {
+static const struct address_space_operations hugetlbfs_aops = {
        .readpage       = hugetlbfs_readpage,
        .prepare_write  = hugetlbfs_prepare_write,
        .commit_write   = hugetlbfs_commit_write,
index 3a2446a27d2c29c9bd6172f8f4e17b9871453d3e..f42961eb983b476f66e591939e42450eb64641d0 100644 (file)
@@ -102,7 +102,7 @@ static kmem_cache_t * inode_cachep __read_mostly;
 
 static struct inode *alloc_inode(struct super_block *sb)
 {
-       static struct address_space_operations empty_aops;
+       static const struct address_space_operations empty_aops;
        static struct inode_operations empty_iops;
        static const struct file_operations empty_fops;
        struct inode *inode;
index 4917315db732e881cecbd50e89573333205d9959..3a39158cca964384e12d73bdbf9b4f7b84c645c6 100644 (file)
@@ -312,7 +312,7 @@ eio:
        return err;
 }
 
-struct address_space_operations zisofs_aops = {
+const struct address_space_operations zisofs_aops = {
        .readpage = zisofs_readpage,
        /* No sync_page operation supported? */
        /* No bmap operation supported */
index 3f9c8ba1fa1f95db3c3e622a17cefd5533087eee..bb11c7fb4019b4c8c1a860f661e704158d8a1321 100644 (file)
@@ -1054,7 +1054,7 @@ static sector_t _isofs_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping,block,isofs_get_block);
 }
 
-static struct address_space_operations isofs_aops = {
+static const struct address_space_operations isofs_aops = {
        .readpage = isofs_readpage,
        .sync_page = block_sync_page,
        .bmap = _isofs_bmap
index b87ba066f5e76f42debee19fcfb5336c896f33f9..e6308c8b57359e728be75de3e23d9e1b2cb974fb 100644 (file)
@@ -176,5 +176,5 @@ isofs_normalize_block_and_offset(struct iso_directory_record* de,
 
 extern struct inode_operations isofs_dir_inode_operations;
 extern const struct file_operations isofs_dir_operations;
-extern struct address_space_operations isofs_symlink_aops;
+extern const struct address_space_operations isofs_symlink_aops;
 extern struct export_operations isofs_export_ops;
index 4326cb47f8fa267667311d2b65b361aa66508858..f3a1db3098deadef58b46d7cec786d9fe8c6dae9 100644 (file)
@@ -754,6 +754,6 @@ error:
        return -EIO;
 }
 
-struct address_space_operations isofs_symlink_aops = {
+const struct address_space_operations isofs_symlink_aops = {
        .readpage = rock_ridge_symlink_readpage
 };
index d78485d101c21e203b669afe23aed5f7fcc5a771..2737957091555fd20e6cd04fd528c871e35b1187 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #ifdef CONFIG_ZISOFS
-extern struct address_space_operations zisofs_aops;
+extern const struct address_space_operations zisofs_aops;
 extern int __init zisofs_init(void);
 extern void zisofs_cleanup(void);
 #endif
index 7f96b5cb67816109e38a51b79a6ee80364e48c5d..8c9b28dff1197d85a3a720f2988b25834f7c495b 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/suspend.h>
 #include <linux/pagemap.h>
 #include <linux/kthread.h>
+#include <linux/poison.h>
 #include <linux/proc_fs.h>
 
 #include <asm/uaccess.h>
@@ -1675,7 +1676,7 @@ static void journal_free_journal_head(struct journal_head *jh)
 {
 #ifdef CONFIG_JBD_DEBUG
        atomic_dec(&nr_journal_heads);
-       memset(jh, 0x5b, sizeof(*jh));
+       memset(jh, JBD_POISON_FREE, sizeof(*jh));
 #endif
        kmem_cache_free(journal_head_cache, jh);
 }
index 9e46ea6da75205e949d5d0c7d0df143c5650a4e5..93068697a9bf2cf5b8a438ea96cf72da2d59be1a 100644 (file)
@@ -59,7 +59,7 @@ static const struct file_operations jffs_file_operations;
 static struct inode_operations jffs_file_inode_operations;
 static const struct file_operations jffs_dir_operations;
 static struct inode_operations jffs_dir_inode_operations;
-static struct address_space_operations jffs_address_operations;
+static const struct address_space_operations jffs_address_operations;
 
 kmem_cache_t     *node_cache = NULL;
 kmem_cache_t     *fm_cache = NULL;
@@ -1614,7 +1614,7 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 } /* jffs_ioctl()  */
 
 
-static struct address_space_operations jffs_address_operations = {
+static const struct address_space_operations jffs_address_operations = {
        .readpage       = jffs_readpage,
        .prepare_write  = jffs_prepare_write,
        .commit_write   = jffs_commit_write,
index 320dd48b834ee48beaa821daede6fd1d2c9f99ae..9c2077e7e081c7375b3df564fa1b8e3b6e2d4722 100644 (file)
@@ -267,6 +267,8 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        }
 
        rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
+       if (!value && rc == -ENODATA)
+               rc = 0;
        if (value)
                kfree(value);
        if (!rc) {
index b8886f048eaad020cce632318b50d4a02cdfb737..ad0121088dde3883ec964e6e90568b0abffe4733 100644 (file)
@@ -225,7 +225,6 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
                           at the end of the linked list. Stash it and continue
                           from the beginning of the list */
                        ic = (struct jffs2_inode_cache *)(*prev);
-                       BUG_ON(ic->class != RAWNODE_CLASS_INODE_CACHE);
                        prev = &ic->nodes;
                        continue;
                }
@@ -249,7 +248,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
 
        /* PARANOIA */
        if (!ic) {
-               printk(KERN_WARNING "inode_cache not found in remove_node_refs()!!\n");
+               JFFS2_WARNING("inode_cache/xattr_datum/xattr_ref"
+                             " not found in remove_node_refs()!!\n");
                return;
        }
 
@@ -274,8 +274,19 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
                printk("\n");
        });
 
-       if (ic->nodes == (void *)ic && ic->nlink == 0)
-               jffs2_del_ino_cache(c, ic);
+       switch (ic->class) {
+#ifdef CONFIG_JFFS2_FS_XATTR
+               case RAWNODE_CLASS_XATTR_DATUM:
+                       jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
+                       break;
+               case RAWNODE_CLASS_XATTR_REF:
+                       jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
+                       break;
+#endif
+               default:
+                       if (ic->nodes == (void *)ic && ic->nlink == 0)
+                               jffs2_del_ino_cache(c, ic);
+       }
 }
 
 void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
index bb8844f40e48e3ecfd6327496a470ffc7bff6814..3ed6e3e120b602fb814051606dc7fc7f89edc430 100644 (file)
@@ -62,7 +62,7 @@ struct inode_operations jffs2_file_inode_operations =
        .removexattr =  jffs2_removexattr
 };
 
-struct address_space_operations jffs2_file_address_operations =
+const struct address_space_operations jffs2_file_address_operations =
 {
        .readpage =     jffs2_readpage,
        .prepare_write =jffs2_prepare_write,
index 2900ec3ec3afb79614a5479179880d0682dddf20..97caa77d60cf23db5ce8dc98848780e2a1caf49c 100644 (file)
@@ -227,8 +227,6 @@ void jffs2_clear_inode (struct inode *inode)
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
 
        D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
-
-       jffs2_xattr_delete_inode(c, f->inocache);
        jffs2_do_clear_inode(c, f);
 }
 
index 477c526d638b979efb7506ba18195ad9b14b2269..daff3341ff92b58cb72916678f69603e64ed5972 100644 (file)
@@ -165,6 +165,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                        D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
                                  ic->ino));
                        spin_unlock(&c->inocache_lock);
+                       jffs2_xattr_delete_inode(c, ic);
                        continue;
                }
                switch(ic->state) {
@@ -275,13 +276,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
         * We can decide whether this node is inode or xattr by ic->class.     */
        if (ic->class == RAWNODE_CLASS_XATTR_DATUM
            || ic->class == RAWNODE_CLASS_XATTR_REF) {
-               BUG_ON(raw->next_in_ino != (void *)ic);
                spin_unlock(&c->erase_completion_lock);
 
                if (ic->class == RAWNODE_CLASS_XATTR_DATUM) {
-                       ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
+                       ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic, raw);
                } else {
-                       ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
+                       ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw);
                }
                goto release_sem;
        }
index 935fec1b1201bdea3cfa25a0cf665ea6f69ed028..b98594992eed530a7431a8db7c85f104ba734d73 100644 (file)
@@ -119,8 +119,11 @@ struct jffs2_sb_info {
 #ifdef CONFIG_JFFS2_FS_XATTR
 #define XATTRINDEX_HASHSIZE    (57)
        uint32_t highest_xid;
+       uint32_t highest_xseqno;
        struct list_head xattrindex[XATTRINDEX_HASHSIZE];
        struct list_head xattr_unchecked;
+       struct list_head xattr_dead_list;
+       struct jffs2_xattr_ref *xref_dead_list;
        struct jffs2_xattr_ref *xref_temp;
        struct rw_semaphore xattr_sem;
        uint32_t xdatum_mem_usage;
index 4889d0700c0e6a32e7e998bf2785438f301613dd..8310c95478e9201dfbe2422bb640340aa1c32e90 100644 (file)
@@ -291,6 +291,7 @@ struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void)
 
        memset(xd, 0, sizeof(struct jffs2_xattr_datum));
        xd->class = RAWNODE_CLASS_XATTR_DATUM;
+       xd->node = (void *)xd;
        INIT_LIST_HEAD(&xd->xindex);
        return xd;
 }
@@ -309,6 +310,7 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void)
 
        memset(ref, 0, sizeof(struct jffs2_xattr_ref));
        ref->class = RAWNODE_CLASS_XATTR_REF;
+       ref->node = (void *)ref;
        return ref;
 }
 
index 927dfe42ba76cab92b6fae6a39c09baa71d7f607..7675b33396c7d7c307c803d0a3db57c95e8371a7 100644 (file)
@@ -906,6 +906,9 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
 {
        struct jffs2_inode_cache **prev;
 
+#ifdef CONFIG_JFFS2_FS_XATTR
+       BUG_ON(old->xref);
+#endif
        dbg_inocache("del %p (ino #%u)\n", old, old->ino);
        spin_lock(&c->inocache_lock);
 
index ac0c350ed7d7bbebad5b2bb69d6f453ea3893c80..d88376992ed9b094cc23f7b75f7b8c07870468ba 100644 (file)
@@ -683,19 +683,26 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                spin_lock(&c->erase_completion_lock);
 
                ic = jffs2_raw_ref_to_ic(ref);
-               /* It seems we should never call jffs2_mark_node_obsolete() for
-                  XATTR nodes.... yet. Make sure we notice if/when we change
-                  that :) */
-               BUG_ON(ic->class != RAWNODE_CLASS_INODE_CACHE);
                for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino))
                        ;
 
                *p = ref->next_in_ino;
                ref->next_in_ino = NULL;
 
-               if (ic->nodes == (void *)ic && ic->nlink == 0)
-                       jffs2_del_ino_cache(c, ic);
-
+               switch (ic->class) {
+#ifdef CONFIG_JFFS2_FS_XATTR
+                       case RAWNODE_CLASS_XATTR_DATUM:
+                               jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
+                               break;
+                       case RAWNODE_CLASS_XATTR_REF:
+                               jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
+                               break;
+#endif
+                       default:
+                               if (ic->nodes == (void *)ic && ic->nlink == 0)
+                                       jffs2_del_ino_cache(c, ic);
+                               break;
+               }
                spin_unlock(&c->erase_completion_lock);
        }
 
index 6b522356540555c15c9cb9e37d2a8a9b317999be..9f41fc01a371b7b1a87d1eff853db3cc46d0018c 100644 (file)
@@ -158,7 +158,7 @@ extern struct inode_operations jffs2_dir_inode_operations;
 /* file.c */
 extern const struct file_operations jffs2_file_operations;
 extern struct inode_operations jffs2_file_inode_operations;
-extern struct address_space_operations jffs2_file_address_operations;
+extern const struct address_space_operations jffs2_file_address_operations;
 int jffs2_fsync(struct file *, struct dentry *, int);
 int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
 
index 5fec012b02ed59a1fa5f8ca871849af4c24e4e40..cc1899268c439a0c68e8bc877c6f4c56854bd3ba 100644 (file)
@@ -968,6 +968,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
        struct jffs2_full_dirent *fd, *fds;
        int deleted;
 
+       jffs2_xattr_delete_inode(c, f->inocache);
        down(&f->sem);
        deleted = f->inocache && !f->inocache->nlink;
 
index 61618080b86f0a9bfe3202e39c8e452f13a21ec5..2bfdc33752d38c69c959729d5d9f462882ef54f6 100644 (file)
@@ -317,20 +317,23 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
                                 struct jffs2_summary *s)
 {
        struct jffs2_xattr_datum *xd;
-       uint32_t totlen, crc;
+       uint32_t xid, version, totlen, crc;
        int err;
 
        crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4);
        if (crc != je32_to_cpu(rx->node_crc)) {
-               if (je32_to_cpu(rx->node_crc) != 0xffffffff)
-                       JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-                                     ofs, je32_to_cpu(rx->node_crc), crc);
+               JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+                             ofs, je32_to_cpu(rx->node_crc), crc);
                if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen))))
                        return err;
                return 0;
        }
 
-       totlen = PAD(sizeof(*rx) + rx->name_len + 1 + je16_to_cpu(rx->value_len));
+       xid = je32_to_cpu(rx->xid);
+       version = je32_to_cpu(rx->version);
+
+       totlen = PAD(sizeof(struct jffs2_raw_xattr)
+                       + rx->name_len + 1 + je16_to_cpu(rx->value_len));
        if (totlen != je32_to_cpu(rx->totlen)) {
                JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
                              ofs, je32_to_cpu(rx->totlen), totlen);
@@ -339,22 +342,24 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
                return 0;
        }
 
-       xd = jffs2_setup_xattr_datum(c, je32_to_cpu(rx->xid), je32_to_cpu(rx->version));
-       if (IS_ERR(xd)) {
-               if (PTR_ERR(xd) == -EEXIST) {
-                       if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rx->totlen)))))
-                               return err;
-                       return 0;
-               }
+       xd = jffs2_setup_xattr_datum(c, xid, version);
+       if (IS_ERR(xd))
                return PTR_ERR(xd);
-       }
-       xd->xprefix = rx->xprefix;
-       xd->name_len = rx->name_len;
-       xd->value_len = je16_to_cpu(rx->value_len);
-       xd->data_crc = je32_to_cpu(rx->data_crc);
 
-       xd->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL);
-       /* FIXME */ xd->node->next_in_ino = (void *)xd;
+       if (xd->version > version) {
+               struct jffs2_raw_node_ref *raw
+                       = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL);
+               raw->next_in_ino = xd->node->next_in_ino;
+               xd->node->next_in_ino = raw;
+       } else {
+               xd->version = version;
+               xd->xprefix = rx->xprefix;
+               xd->name_len = rx->name_len;
+               xd->value_len = je16_to_cpu(rx->value_len);
+               xd->data_crc = je32_to_cpu(rx->data_crc);
+
+               jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, (void *)xd);
+       }
 
        if (jffs2_sum_active())
                jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset);
@@ -373,9 +378,8 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock
 
        crc = crc32(0, rr, sizeof(*rr) - 4);
        if (crc != je32_to_cpu(rr->node_crc)) {
-               if (je32_to_cpu(rr->node_crc) != 0xffffffff)
-                       JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-                                     ofs, je32_to_cpu(rr->node_crc), crc);
+               JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+                             ofs, je32_to_cpu(rr->node_crc), crc);
                if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rr->totlen)))))
                        return err;
                return 0;
@@ -395,6 +399,7 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock
                return -ENOMEM;
 
        /* BEFORE jffs2_build_xattr_subsystem() called, 
+        * and AFTER xattr_ref is marked as a dead xref,
         * ref->xid is used to store 32bit xid, xd is not used
         * ref->ino is used to store 32bit inode-number, ic is not used
         * Thoes variables are declared as union, thus using those
@@ -404,11 +409,13 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock
         */
        ref->ino = je32_to_cpu(rr->ino);
        ref->xid = je32_to_cpu(rr->xid);
+       ref->xseqno = je32_to_cpu(rr->xseqno);
+       if (ref->xseqno > c->highest_xseqno)
+               c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER);
        ref->next = c->xref_temp;
        c->xref_temp = ref;
 
-       ref->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), NULL);
-       /* FIXME */ ref->node->next_in_ino = (void *)ref;
+       jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), (void *)ref);
 
        if (jffs2_sum_active())
                jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset);
index be1acc3dad97a7d340b56c82c5db59fd64436ce3..c19bd476e8ec785abbdcaf9edc9c9ff2e0446678 100644 (file)
@@ -5,7 +5,7 @@
  *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
  *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
  *                     University of Szeged, Hungary
- *               2005  KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *               2006  KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
@@ -310,8 +310,6 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
 #ifdef CONFIG_JFFS2_FS_XATTR
                case JFFS2_NODETYPE_XATTR: {
                        struct jffs2_sum_xattr_mem *temp;
-                       if (je32_to_cpu(node->x.version) == 0xffffffff)
-                               return 0;
                        temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
                        if (!temp)
                                goto no_mem;
@@ -327,10 +325,6 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
                }
                case JFFS2_NODETYPE_XREF: {
                        struct jffs2_sum_xref_mem *temp;
-
-                       if (je32_to_cpu(node->r.ino) == 0xffffffff
-                           && je32_to_cpu(node->r.xid) == 0xffffffff)
-                               return 0;
                        temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
                        if (!temp)
                                goto no_mem;
@@ -483,22 +477,20 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
 
                                xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
                                                                je32_to_cpu(spx->version));
-                               if (IS_ERR(xd)) {
-                                       if (PTR_ERR(xd) == -EEXIST) {
-                                               /* a newer version of xd exists */
-                                               if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(spx->totlen))))
-                                                       return err;
-                                               sp += JFFS2_SUMMARY_XATTR_SIZE;
-                                               break;
-                                       }
-                                       JFFS2_NOTICE("allocation of xattr_datum failed\n");
+                               if (IS_ERR(xd))
                                        return PTR_ERR(xd);
+                               if (xd->version > je32_to_cpu(spx->version)) {
+                                       /* node is not the newest one */
+                                       struct jffs2_raw_node_ref *raw
+                                               = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
+                                                                   PAD(je32_to_cpu(spx->totlen)), NULL);
+                                       raw->next_in_ino = xd->node->next_in_ino;
+                                       xd->node->next_in_ino = raw;
+                               } else {
+                                       xd->version = je32_to_cpu(spx->version);
+                                       sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
+                                                         PAD(je32_to_cpu(spx->totlen)), (void *)xd);
                                }
-
-                               xd->node = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
-                                                            PAD(je32_to_cpu(spx->totlen)), NULL);
-                               /* FIXME */ xd->node->next_in_ino = (void *)xd;
-
                                *pseudo_random += je32_to_cpu(spx->xid);
                                sp += JFFS2_SUMMARY_XATTR_SIZE;
 
@@ -519,14 +511,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                        JFFS2_NOTICE("allocation of xattr_datum failed\n");
                                        return -ENOMEM;
                                }
-                               ref->ino = 0xfffffffe;
-                               ref->xid = 0xfffffffd;
                                ref->next = c->xref_temp;
                                c->xref_temp = ref;
 
-                               ref->node = sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
-                                                             PAD(sizeof(struct jffs2_raw_xref)), NULL);
-                               /* FIXME */ ref->node->next_in_ino = (void *)ref;
+                               sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
+                                                 PAD(sizeof(struct jffs2_raw_xref)), (void *)ref);
 
                                *pseudo_random += ref->node->flash_offset;
                                sp += JFFS2_SUMMARY_XREF_SIZE;
index 2d82e250be34e234ec6f533b8f37b1620b88e04c..18e66dbf23b497d456a191c75c9d7cb1b52edd65 100644 (file)
  * xattr_datum_hashkey(xprefix, xname, xvalue, xsize)
  *   is used to calcurate xdatum hashkey. The reminder of hashkey into XATTRINDEX_HASHSIZE is
  *   the index of the xattr name/value pair cache (c->xattrindex).
+ * is_xattr_datum_unchecked(c, xd)
+ *   returns 1, if xdatum contains any unchecked raw nodes. if all raw nodes are not
+ *   unchecked, it returns 0.
  * unload_xattr_datum(c, xd)
  *   is used to release xattr name/value pair and detach from c->xattrindex.
  * reclaim_xattr_datum(c)
  *   is used to reclaim xattr name/value pairs on the xattr name/value pair cache when
  *   memory usage by cache is over c->xdatum_mem_threshold. Currentry, this threshold 
  *   is hard coded as 32KiB.
- * delete_xattr_datum_node(c, xd)
- *   is used to delete a jffs2 node is dominated by xdatum. When EBS(Erase Block Summary) is
- *   enabled, it overwrites the obsolete node by myself.
- * delete_xattr_datum(c, xd)
- *   is used to delete jffs2_xattr_datum object. It must be called with 0-value of reference
- *   counter. (It means how many jffs2_xattr_ref object refers this xdatum.)
  * do_verify_xattr_datum(c, xd)
  *   is used to load the xdatum informations without name/value pair from the medium.
  *   It's necessary once, because those informations are not collected during mounting
  *   is used to write xdatum to medium. xd->version will be incremented.
  * create_xattr_datum(c, xprefix, xname, xvalue, xsize)
  *   is used to create new xdatum and write to medium.
+ * delete_xattr_datum(c, xd)
+ *   is used to delete a xdatum. It marks xd JFFS2_XFLAGS_DEAD, and allows
+ *   GC to reclaim those physical nodes.
  * -------------------------------------------------- */
-
 static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize)
 {
        int name_len = strlen(xname);
@@ -62,6 +61,22 @@ static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *
        return crc32(xprefix, xname, name_len) ^ crc32(xprefix, xvalue, xsize);
 }
 
+static int is_xattr_datum_unchecked(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+       struct jffs2_raw_node_ref *raw;
+       int rc = 0;
+
+       spin_lock(&c->erase_completion_lock);
+       for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
+               if (ref_flags(raw) == REF_UNCHECKED) {
+                       rc = 1;
+                       break;
+               }
+       }
+       spin_unlock(&c->erase_completion_lock);
+       return rc;
+}
+
 static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
        /* must be called under down_write(xattr_sem) */
@@ -107,77 +122,33 @@ static void reclaim_xattr_datum(struct jffs2_sb_info *c)
                     before, c->xdatum_mem_usage, before - c->xdatum_mem_usage);
 }
 
-static void delete_xattr_datum_node(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
-{
-       /* must be called under down_write(xattr_sem) */
-       struct jffs2_raw_xattr rx;
-       size_t length;
-       int rc;
-
-       if (!xd->node) {
-               JFFS2_WARNING("xdatum (xid=%u) is removed twice.\n", xd->xid);
-               return;
-       }
-       if (jffs2_sum_active()) {
-               memset(&rx, 0xff, sizeof(struct jffs2_raw_xattr));
-               rc = jffs2_flash_read(c, ref_offset(xd->node),
-                                     sizeof(struct jffs2_unknown_node),
-                                     &length, (char *)&rx);
-               if (rc || length != sizeof(struct jffs2_unknown_node)) {
-                       JFFS2_ERROR("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",
-                                   rc, sizeof(struct jffs2_unknown_node),
-                                   length, ref_offset(xd->node));
-               }
-               rc = jffs2_flash_write(c, ref_offset(xd->node), sizeof(rx),
-                                      &length, (char *)&rx);
-               if (rc || length != sizeof(struct jffs2_raw_xattr)) {
-                       JFFS2_ERROR("jffs2_flash_write()=%d, req=%zu, wrote=%zu ar %#08x\n",
-                                   rc, sizeof(rx), length, ref_offset(xd->node));
-               }
-       }
-       spin_lock(&c->erase_completion_lock);
-       xd->node->next_in_ino = NULL;
-       spin_unlock(&c->erase_completion_lock);
-       jffs2_mark_node_obsolete(c, xd->node);
-       xd->node = NULL;
-}
-
-static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
-{
-       /* must be called under down_write(xattr_sem) */
-       BUG_ON(xd->refcnt);
-
-       unload_xattr_datum(c, xd);
-       if (xd->node) {
-               delete_xattr_datum_node(c, xd);
-               xd->node = NULL;
-       }
-       jffs2_free_xattr_datum(xd);
-}
-
 static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
        /* must be called under down_write(xattr_sem) */
        struct jffs2_eraseblock *jeb;
+       struct jffs2_raw_node_ref *raw;
        struct jffs2_raw_xattr rx;
        size_t readlen;
-       uint32_t crc, totlen;
+       uint32_t crc, offset, totlen;
        int rc;
 
-       BUG_ON(!xd->node);
-       BUG_ON(ref_flags(xd->node) != REF_UNCHECKED);
+       spin_lock(&c->erase_completion_lock);
+       offset = ref_offset(xd->node);
+       if (ref_flags(xd->node) == REF_PRISTINE)
+               goto complete;
+       spin_unlock(&c->erase_completion_lock);
 
-       rc = jffs2_flash_read(c, ref_offset(xd->node), sizeof(rx), &readlen, (char *)&rx);
+       rc = jffs2_flash_read(c, offset, sizeof(rx), &readlen, (char *)&rx);
        if (rc || readlen != sizeof(rx)) {
                JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",
-                             rc, sizeof(rx), readlen, ref_offset(xd->node));
+                             rc, sizeof(rx), readlen, offset);
                return rc ? rc : -EIO;
        }
        crc = crc32(0, &rx, sizeof(rx) - 4);
        if (crc != je32_to_cpu(rx.node_crc)) {
-               if (je32_to_cpu(rx.node_crc) != 0xffffffff)
-                       JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-                                   ref_offset(xd->node), je32_to_cpu(rx.hdr_crc), crc);
+               JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+                           offset, je32_to_cpu(rx.hdr_crc), crc);
+               xd->flags |= JFFS2_XFLAGS_INVALID;
                return EIO;
        }
        totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
@@ -188,11 +159,12 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
            || je32_to_cpu(rx.version) != xd->version) {
                JFFS2_ERROR("inconsistent xdatum at %#08x, magic=%#04x/%#04x, "
                            "nodetype=%#04x/%#04x, totlen=%u/%u, xid=%u/%u, version=%u/%u\n",
-                           ref_offset(xd->node), je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK,
+                           offset, je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK,
                            je16_to_cpu(rx.nodetype), JFFS2_NODETYPE_XATTR,
                            je32_to_cpu(rx.totlen), totlen,
                            je32_to_cpu(rx.xid), xd->xid,
                            je32_to_cpu(rx.version), xd->version);
+               xd->flags |= JFFS2_XFLAGS_INVALID;
                return EIO;
        }
        xd->xprefix = rx.xprefix;
@@ -200,14 +172,17 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
        xd->value_len = je16_to_cpu(rx.value_len);
        xd->data_crc = je32_to_cpu(rx.data_crc);
 
-       /* This JFFS2_NODETYPE_XATTR node is checked */
-       jeb = &c->blocks[ref_offset(xd->node) / c->sector_size];
-       totlen = PAD(je32_to_cpu(rx.totlen));
-
        spin_lock(&c->erase_completion_lock);
-       c->unchecked_size -= totlen; c->used_size += totlen;
-       jeb->unchecked_size -= totlen; jeb->used_size += totlen;
-       xd->node->flash_offset = ref_offset(xd->node) | REF_PRISTINE;
+ complete:
+       for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
+               jeb = &c->blocks[ref_offset(raw) / c->sector_size];
+               totlen = PAD(ref_totlen(c, jeb, raw));
+               if (ref_flags(raw) == REF_UNCHECKED) {
+                       c->unchecked_size -= totlen; c->used_size += totlen;
+                       jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+               }
+               raw->flash_offset = ref_offset(raw) | ((xd->node==raw) ? REF_PRISTINE : REF_NORMAL);
+       }
        spin_unlock(&c->erase_completion_lock);
 
        /* unchecked xdatum is chained with c->xattr_unchecked */
@@ -227,7 +202,6 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum
        uint32_t crc, length;
        int i, ret, retry = 0;
 
-       BUG_ON(!xd->node);
        BUG_ON(ref_flags(xd->node) != REF_PRISTINE);
        BUG_ON(!list_empty(&xd->xindex));
  retry:
@@ -253,6 +227,7 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum
                              " at %#08x, read: 0x%08x calculated: 0x%08x\n",
                              ref_offset(xd->node), xd->data_crc, crc);
                kfree(data);
+               xd->flags |= JFFS2_XFLAGS_INVALID;
                return EIO;
        }
 
@@ -286,16 +261,14 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
         * rc > 0 : Unrecoverable error, this node should be deleted.
         */
        int rc = 0;
-       BUG_ON(xd->xname);
-       if (!xd->node)
+
+       BUG_ON(xd->flags & JFFS2_XFLAGS_DEAD);
+       if (xd->xname)
+               return 0;
+       if (xd->flags & JFFS2_XFLAGS_INVALID)
                return EIO;
-       if (unlikely(ref_flags(xd->node) != REF_PRISTINE)) {
+       if (unlikely(is_xattr_datum_unchecked(c, xd)))
                rc = do_verify_xattr_datum(c, xd);
-               if (rc > 0) {
-                       list_del_init(&xd->xindex);
-                       delete_xattr_datum_node(c, xd);
-               }
-       }
        if (!rc)
                rc = do_load_xattr_datum(c, xd);
        return rc;
@@ -304,7 +277,6 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
 static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
        /* must be called under down_write(xattr_sem) */
-       struct jffs2_raw_node_ref *raw;
        struct jffs2_raw_xattr rx;
        struct kvec vecs[2];
        size_t length;
@@ -312,14 +284,16 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
        uint32_t phys_ofs = write_ofs(c);
 
        BUG_ON(!xd->xname);
+       BUG_ON(xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID));
 
        vecs[0].iov_base = &rx;
-       vecs[0].iov_len = PAD(sizeof(rx));
+       vecs[0].iov_len = sizeof(rx);
        vecs[1].iov_base = xd->xname;
        vecs[1].iov_len = xd->name_len + 1 + xd->value_len;
        totlen = vecs[0].iov_len + vecs[1].iov_len;
 
        /* Setup raw-xattr */
+       memset(&rx, 0, sizeof(rx));
        rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
        rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
        rx.totlen = cpu_to_je32(PAD(totlen));
@@ -343,14 +317,8 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
 
                return rc;
        }
-
        /* success */
-       raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), NULL);
-       /* FIXME */ raw->next_in_ino = (void *)xd;
-
-       if (xd->node)
-               delete_xattr_datum_node(c, xd);
-       xd->node = raw;
+       jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), (void *)xd);
 
        dbg_xattr("success on saving xdatum (xid=%u, version=%u, xprefix=%u, xname='%s')\n",
                  xd->xid, xd->version, xd->xprefix, xd->xname);
@@ -377,7 +345,7 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
                    && xd->value_len==xsize
                    && !strcmp(xd->xname, xname)
                    && !memcmp(xd->xvalue, xvalue, xsize)) {
-                       xd->refcnt++;
+                       atomic_inc(&xd->refcnt);
                        return xd;
                }
        }
@@ -397,7 +365,7 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
        strcpy(data, xname);
        memcpy(data + name_len + 1, xvalue, xsize);
 
-       xd->refcnt = 1;
+       atomic_set(&xd->refcnt, 1);
        xd->xid = ++c->highest_xid;
        xd->flags |= JFFS2_XFLAGS_HOT;
        xd->xprefix = xprefix;
@@ -426,20 +394,36 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
        return xd;
 }
 
+static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+       /* must be called under down_write(xattr_sem) */
+       BUG_ON(atomic_read(&xd->refcnt));
+
+       unload_xattr_datum(c, xd);
+       xd->flags |= JFFS2_XFLAGS_DEAD;
+       spin_lock(&c->erase_completion_lock);
+       if (xd->node == (void *)xd) {
+               BUG_ON(!(xd->flags & JFFS2_XFLAGS_INVALID));
+               jffs2_free_xattr_datum(xd);
+       } else {
+               list_add(&xd->xindex, &c->xattr_dead_list);
+       }
+       spin_unlock(&c->erase_completion_lock);
+       dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xd->xid, xd->version);
+}
+
 /* -------- xref related functions ------------------
  * verify_xattr_ref(c, ref)
  *   is used to load xref information from medium. Because summary data does not
  *   contain xid/ino, it's necessary to verify once while mounting process.
- * delete_xattr_ref_node(c, ref)
- *   is used to delete a jffs2 node is dominated by xref. When EBS is enabled,
- *   it overwrites the obsolete node by myself. 
- * delete_xattr_ref(c, ref)
- *   is used to delete jffs2_xattr_ref object. If the reference counter of xdatum
- *   is refered by this xref become 0, delete_xattr_datum() is called later.
  * save_xattr_ref(c, ref)
- *   is used to write xref to medium.
+ *   is used to write xref to medium. If delete marker is marked, it write
+ *   a delete marker of xref into medium.
  * create_xattr_ref(c, ic, xd)
  *   is used to create a new xref and write to medium.
+ * delete_xattr_ref(c, ref)
+ *   is used to delete jffs2_xattr_ref. It marks xref XREF_DELETE_MARKER,
+ *   and allows GC to reclaim those physical nodes.
  * jffs2_xattr_delete_inode(c, ic)
  *   is called to remove xrefs related to obsolete inode when inode is unlinked.
  * jffs2_xattr_free_inode(c, ic)
@@ -450,25 +434,29 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
 static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
 {
        struct jffs2_eraseblock *jeb;
+       struct jffs2_raw_node_ref *raw;
        struct jffs2_raw_xref rr;
        size_t readlen;
-       uint32_t crc, totlen;
+       uint32_t crc, offset, totlen;
        int rc;
 
-       BUG_ON(ref_flags(ref->node) != REF_UNCHECKED);
+       spin_lock(&c->erase_completion_lock);
+       if (ref_flags(ref->node) != REF_UNCHECKED)
+               goto complete;
+       offset = ref_offset(ref->node);
+       spin_unlock(&c->erase_completion_lock);
 
-       rc = jffs2_flash_read(c, ref_offset(ref->node), sizeof(rr), &readlen, (char *)&rr);
+       rc = jffs2_flash_read(c, offset, sizeof(rr), &readlen, (char *)&rr);
        if (rc || sizeof(rr) != readlen) {
                JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu, at %#08x\n",
-                             rc, sizeof(rr), readlen, ref_offset(ref->node));
+                             rc, sizeof(rr), readlen, offset);
                return rc ? rc : -EIO;
        }
        /* obsolete node */
        crc = crc32(0, &rr, sizeof(rr) - 4);
        if (crc != je32_to_cpu(rr.node_crc)) {
-               if (je32_to_cpu(rr.node_crc) != 0xffffffff)
-                       JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-                                   ref_offset(ref->node), je32_to_cpu(rr.node_crc), crc);
+               JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+                           offset, je32_to_cpu(rr.node_crc), crc);
                return EIO;
        }
        if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK
@@ -476,22 +464,28 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
            || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) {
                JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, "
                            "nodetype=%#04x/%#04x, totlen=%u/%zu\n",
-                           ref_offset(ref->node), je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
+                           offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
                            je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF,
                            je32_to_cpu(rr.totlen), PAD(sizeof(rr)));
                return EIO;
        }
        ref->ino = je32_to_cpu(rr.ino);
        ref->xid = je32_to_cpu(rr.xid);
-
-       /* fixup superblock/eraseblock info */
-       jeb = &c->blocks[ref_offset(ref->node) / c->sector_size];
-       totlen = PAD(sizeof(rr));
+       ref->xseqno = je32_to_cpu(rr.xseqno);
+       if (ref->xseqno > c->highest_xseqno)
+               c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER);
 
        spin_lock(&c->erase_completion_lock);
-       c->unchecked_size -= totlen; c->used_size += totlen;
-       jeb->unchecked_size -= totlen; jeb->used_size += totlen;
-       ref->node->flash_offset = ref_offset(ref->node) | REF_PRISTINE;
+ complete:
+       for (raw=ref->node; raw != (void *)ref; raw=raw->next_in_ino) {
+               jeb = &c->blocks[ref_offset(raw) / c->sector_size];
+               totlen = PAD(ref_totlen(c, jeb, raw));
+               if (ref_flags(raw) == REF_UNCHECKED) {
+                       c->unchecked_size -= totlen; c->used_size += totlen;
+                       jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+               }
+               raw->flash_offset = ref_offset(raw) | ((ref->node==raw) ? REF_PRISTINE : REF_NORMAL);
+       }
        spin_unlock(&c->erase_completion_lock);
 
        dbg_xattr("success on verifying xref (ino=%u, xid=%u) at %#08x\n",
@@ -499,58 +493,12 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
        return 0;
 }
 
-static void delete_xattr_ref_node(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
-{
-       struct jffs2_raw_xref rr;
-       size_t length;
-       int rc;
-
-       if (jffs2_sum_active()) {
-               memset(&rr, 0xff, sizeof(rr));
-               rc = jffs2_flash_read(c, ref_offset(ref->node),
-                                     sizeof(struct jffs2_unknown_node),
-                                     &length, (char *)&rr);
-               if (rc || length != sizeof(struct jffs2_unknown_node)) {
-                       JFFS2_ERROR("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",
-                                   rc, sizeof(struct jffs2_unknown_node),
-                                   length, ref_offset(ref->node));
-               }
-               rc = jffs2_flash_write(c, ref_offset(ref->node), sizeof(rr),
-                                      &length, (char *)&rr);
-               if (rc || length != sizeof(struct jffs2_raw_xref)) {
-                       JFFS2_ERROR("jffs2_flash_write()=%d, req=%zu, wrote=%zu at %#08x\n",
-                                   rc, sizeof(rr), length, ref_offset(ref->node));
-               }
-       }
-       spin_lock(&c->erase_completion_lock);
-       ref->node->next_in_ino = NULL;
-       spin_unlock(&c->erase_completion_lock);
-       jffs2_mark_node_obsolete(c, ref->node);
-       ref->node = NULL;
-}
-
-static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
-{
-       /* must be called under down_write(xattr_sem) */
-       struct jffs2_xattr_datum *xd;
-
-       BUG_ON(!ref->node);
-       delete_xattr_ref_node(c, ref);
-
-       xd = ref->xd;
-       xd->refcnt--;
-       if (!xd->refcnt)
-               delete_xattr_datum(c, xd);
-       jffs2_free_xattr_ref(ref);
-}
-
 static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
 {
        /* must be called under down_write(xattr_sem) */
-       struct jffs2_raw_node_ref *raw;
        struct jffs2_raw_xref rr;
        size_t length;
-       uint32_t phys_ofs = write_ofs(c);
+       uint32_t xseqno, phys_ofs = write_ofs(c);
        int ret;
 
        rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -558,8 +506,16 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
        rr.totlen = cpu_to_je32(PAD(sizeof(rr)));
        rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4));
 
-       rr.ino = cpu_to_je32(ref->ic->ino);
-       rr.xid = cpu_to_je32(ref->xd->xid);
+       xseqno = (c->highest_xseqno += 2);
+       if (is_xattr_ref_dead(ref)) {
+               xseqno |= XREF_DELETE_MARKER;
+               rr.ino = cpu_to_je32(ref->ino);
+               rr.xid = cpu_to_je32(ref->xid);
+       } else {
+               rr.ino = cpu_to_je32(ref->ic->ino);
+               rr.xid = cpu_to_je32(ref->xd->xid);
+       }
+       rr.xseqno = cpu_to_je32(xseqno);
        rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4));
 
        ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr);
@@ -572,12 +528,9 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
 
                return ret;
        }
-
-       raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), NULL);
-       /* FIXME */ raw->next_in_ino = (void *)ref;
-       if (ref->node)
-               delete_xattr_ref_node(c, ref);
-       ref->node = raw;
+       /* success */
+       ref->xseqno = xseqno;
+       jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), (void *)ref);
 
        dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid);
 
@@ -610,6 +563,27 @@ static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct
        return ref; /* success */
 }
 
+static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+{
+       /* must be called under down_write(xattr_sem) */
+       struct jffs2_xattr_datum *xd;
+
+       xd = ref->xd;
+       ref->xseqno |= XREF_DELETE_MARKER;
+       ref->ino = ref->ic->ino;
+       ref->xid = ref->xd->xid;
+       spin_lock(&c->erase_completion_lock);
+       ref->next = c->xref_dead_list;
+       c->xref_dead_list = ref;
+       spin_unlock(&c->erase_completion_lock);
+
+       dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n",
+                 ref->ino, ref->xid, ref->xseqno);
+
+       if (atomic_dec_and_test(&xd->refcnt))
+               delete_xattr_datum(c, xd);
+}
+
 void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
 {
        /* It's called from jffs2_clear_inode() on inode removing.
@@ -638,8 +612,7 @@ void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i
        for (ref = ic->xref; ref; ref = _ref) {
                _ref = ref->next;
                xd = ref->xd;
-               xd->refcnt--;
-               if (!xd->refcnt) {
+               if (atomic_dec_and_test(&xd->refcnt)) {
                        unload_xattr_datum(c, xd);
                        jffs2_free_xattr_datum(xd);
                }
@@ -655,7 +628,7 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac
         * duplicate name/value pairs. If duplicate name/value pair would be found,
         * one will be removed.
         */
-       struct jffs2_xattr_ref *ref, *cmp, **pref;
+       struct jffs2_xattr_ref *ref, *cmp, **pref, **pcmp;
        int rc = 0;
 
        if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED))
@@ -673,13 +646,13 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac
                        } else if (unlikely(rc < 0))
                                goto out;
                }
-               for (cmp=ref->next, pref=&ref->next; cmp; pref=&cmp->next, cmp=cmp->next) {
+               for (cmp=ref->next, pcmp=&ref->next; cmp; pcmp=&cmp->next, cmp=cmp->next) {
                        if (!cmp->xd->xname) {
                                ref->xd->flags |= JFFS2_XFLAGS_BIND;
                                rc = load_xattr_datum(c, cmp->xd);
                                ref->xd->flags &= ~JFFS2_XFLAGS_BIND;
                                if (unlikely(rc > 0)) {
-                                       *pref = cmp->next;
+                                       *pcmp = cmp->next;
                                        delete_xattr_ref(c, cmp);
                                        goto retry;
                                } else if (unlikely(rc < 0))
@@ -687,8 +660,13 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac
                        }
                        if (ref->xd->xprefix == cmp->xd->xprefix
                            && !strcmp(ref->xd->xname, cmp->xd->xname)) {
-                               *pref = cmp->next;
-                               delete_xattr_ref(c, cmp);
+                               if (ref->xseqno > cmp->xseqno) {
+                                       *pcmp = cmp->next;
+                                       delete_xattr_ref(c, cmp);
+                               } else {
+                                       *pref = ref->next;
+                                       delete_xattr_ref(c, ref);
+                               }
                                goto retry;
                        }
                }
@@ -719,9 +697,13 @@ void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c)
        for (i=0; i < XATTRINDEX_HASHSIZE; i++)
                INIT_LIST_HEAD(&c->xattrindex[i]);
        INIT_LIST_HEAD(&c->xattr_unchecked);
+       INIT_LIST_HEAD(&c->xattr_dead_list);
+       c->xref_dead_list = NULL;
        c->xref_temp = NULL;
 
        init_rwsem(&c->xattr_sem);
+       c->highest_xid = 0;
+       c->highest_xseqno = 0;
        c->xdatum_mem_usage = 0;
        c->xdatum_mem_threshold = 32 * 1024;    /* Default 32KB */
 }
@@ -751,7 +733,11 @@ void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c)
                _ref = ref->next;
                jffs2_free_xattr_ref(ref);
        }
-       c->xref_temp = NULL;
+
+       for (ref=c->xref_dead_list; ref; ref = _ref) {
+               _ref = ref->next;
+               jffs2_free_xattr_ref(ref);
+       }
 
        for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
                list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
@@ -761,100 +747,143 @@ void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c)
                        jffs2_free_xattr_datum(xd);
                }
        }
+
+       list_for_each_entry_safe(xd, _xd, &c->xattr_dead_list, xindex) {
+               list_del(&xd->xindex);
+               jffs2_free_xattr_datum(xd);
+       }
 }
 
+#define XREF_TMPHASH_SIZE      (128)
 void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
 {
        struct jffs2_xattr_ref *ref, *_ref;
+       struct jffs2_xattr_ref *xref_tmphash[XREF_TMPHASH_SIZE];
        struct jffs2_xattr_datum *xd, *_xd;
        struct jffs2_inode_cache *ic;
-       int i, xdatum_count =0, xdatum_unchecked_count = 0, xref_count = 0;
+       struct jffs2_raw_node_ref *raw;
+       int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0;
+       int xdatum_orphan_count = 0, xref_orphan_count = 0, xref_dead_count = 0;
 
        BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING));
 
-       /* Phase.1 */
+       /* Phase.1 : Merge same xref */
+       for (i=0; i < XREF_TMPHASH_SIZE; i++)
+               xref_tmphash[i] = NULL;
        for (ref=c->xref_temp; ref; ref=_ref) {
+               struct jffs2_xattr_ref *tmp;
+
                _ref = ref->next;
-               /* checking REF_UNCHECKED nodes */
                if (ref_flags(ref->node) != REF_PRISTINE) {
                        if (verify_xattr_ref(c, ref)) {
-                               delete_xattr_ref_node(c, ref);
+                               BUG_ON(ref->node->next_in_ino != (void *)ref);
+                               ref->node->next_in_ino = NULL;
+                               jffs2_mark_node_obsolete(c, ref->node);
                                jffs2_free_xattr_ref(ref);
                                continue;
                        }
                }
-               /* At this point, ref->xid and ref->ino contain XID and inode number.
-                  ref->xd and ref->ic are not valid yet. */
-               xd = jffs2_find_xattr_datum(c, ref->xid);
-               ic = jffs2_get_ino_cache(c, ref->ino);
-               if (!xd || !ic) {
-                       if (ref_flags(ref->node) != REF_UNCHECKED)
-                               JFFS2_WARNING("xref(ino=%u, xid=%u) is orphan. \n",
-                                             ref->ino, ref->xid);
-                       delete_xattr_ref_node(c, ref);
+
+               i = (ref->ino ^ ref->xid) % XREF_TMPHASH_SIZE;
+               for (tmp=xref_tmphash[i]; tmp; tmp=tmp->next) {
+                       if (tmp->ino == ref->ino && tmp->xid == ref->xid)
+                               break;
+               }
+               if (tmp) {
+                       raw = ref->node;
+                       if (ref->xseqno > tmp->xseqno) {
+                               tmp->xseqno = ref->xseqno;
+                               raw->next_in_ino = tmp->node;
+                               tmp->node = raw;
+                       } else {
+                               raw->next_in_ino = tmp->node->next_in_ino;
+                               tmp->node->next_in_ino = raw;
+                       }
                        jffs2_free_xattr_ref(ref);
                        continue;
+               } else {
+                       ref->next = xref_tmphash[i];
+                       xref_tmphash[i] = ref;
                }
-               ref->xd = xd;
-               ref->ic = ic;
-               xd->refcnt++;
-               ref->next = ic->xref;
-               ic->xref = ref;
-               xref_count++;
        }
        c->xref_temp = NULL;
-       /* After this, ref->xid/ino are NEVER used. */
 
-       /* Phase.2 */
+       /* Phase.2 : Bind xref with inode_cache and xattr_datum */
+       for (i=0; i < XREF_TMPHASH_SIZE; i++) {
+               for (ref=xref_tmphash[i]; ref; ref=_ref) {
+                       xref_count++;
+                       _ref = ref->next;
+                       if (is_xattr_ref_dead(ref)) {
+                               ref->next = c->xref_dead_list;
+                               c->xref_dead_list = ref;
+                               xref_dead_count++;
+                               continue;
+                       }
+                       /* At this point, ref->xid and ref->ino contain XID and inode number.
+                          ref->xd and ref->ic are not valid yet. */
+                       xd = jffs2_find_xattr_datum(c, ref->xid);
+                       ic = jffs2_get_ino_cache(c, ref->ino);
+                       if (!xd || !ic) {
+                               dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n",
+                                         ref->ino, ref->xid, ref->xseqno);
+                               ref->xseqno |= XREF_DELETE_MARKER;
+                               ref->next = c->xref_dead_list;
+                               c->xref_dead_list = ref;
+                               xref_orphan_count++;
+                               continue;
+                       }
+                       ref->xd = xd;
+                       ref->ic = ic;
+                       atomic_inc(&xd->refcnt);
+                       ref->next = ic->xref;
+                       ic->xref = ref;
+               }
+       }
+
+       /* Phase.3 : Link unchecked xdatum to xattr_unchecked list */
        for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
                list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
+                       xdatum_count++;
                        list_del_init(&xd->xindex);
-                       if (!xd->refcnt) {
-                               if (ref_flags(xd->node) != REF_UNCHECKED)
-                                       JFFS2_WARNING("orphan xdatum(xid=%u, version=%u) at %#08x\n",
-                                                     xd->xid, xd->version, ref_offset(xd->node));
-                               delete_xattr_datum(c, xd);
+                       if (!atomic_read(&xd->refcnt)) {
+                               dbg_xattr("xdatum(xid=%u, version=%u) is orphan.\n",
+                                         xd->xid, xd->version);
+                               xd->flags |= JFFS2_XFLAGS_DEAD;
+                               list_add(&xd->xindex, &c->xattr_unchecked);
+                               xdatum_orphan_count++;
                                continue;
                        }
-                       if (ref_flags(xd->node) != REF_PRISTINE) {
-                               dbg_xattr("unchecked xdatum(xid=%u) at %#08x\n",
-                                         xd->xid, ref_offset(xd->node));
+                       if (is_xattr_datum_unchecked(c, xd)) {
+                               dbg_xattr("unchecked xdatum(xid=%u, version=%u)\n",
+                                         xd->xid, xd->version);
                                list_add(&xd->xindex, &c->xattr_unchecked);
                                xdatum_unchecked_count++;
                        }
-                       xdatum_count++;
                }
        }
        /* build complete */
-       JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum (%u unchecked) and "
-                    "%u of xref found.\n", xdatum_count, xdatum_unchecked_count, xref_count);
+       JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum"
+                    " (%u unchecked, %u orphan) and "
+                    "%u of xref (%u dead, %u orphan) found.\n",
+                    xdatum_count, xdatum_unchecked_count, xdatum_orphan_count,
+                    xref_count, xref_dead_count, xref_orphan_count);
 }
 
 struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
                                                  uint32_t xid, uint32_t version)
 {
-       struct jffs2_xattr_datum *xd, *_xd;
+       struct jffs2_xattr_datum *xd;
 
-       _xd = jffs2_find_xattr_datum(c, xid);
-       if (_xd) {
-               dbg_xattr("duplicate xdatum (xid=%u, version=%u/%u) at %#08x\n",
-                         xid, version, _xd->version, ref_offset(_xd->node));
-               if (version < _xd->version)
-                       return ERR_PTR(-EEXIST);
-       }
-       xd = jffs2_alloc_xattr_datum();
-       if (!xd)
-               return ERR_PTR(-ENOMEM);
-       xd->xid = xid;
-       xd->version = version;
-       if (xd->xid > c->highest_xid)
-               c->highest_xid = xd->xid;
-       list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]);
-
-       if (_xd) {
-               list_del_init(&_xd->xindex);
-               delete_xattr_datum_node(c, _xd);
-               jffs2_free_xattr_datum(_xd);
+       xd = jffs2_find_xattr_datum(c, xid);
+       if (!xd) {
+               xd = jffs2_alloc_xattr_datum();
+               if (!xd)
+                       return ERR_PTR(-ENOMEM);
+               xd->xid = xid;
+               xd->version = version;
+               if (xd->xid > c->highest_xid)
+                       c->highest_xid = xd->xid;
+               list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]);
        }
        return xd;
 }
@@ -1080,9 +1109,23 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
                                goto out;
                        }
                        if (!buffer) {
-                               *pref = ref->next;
-                               delete_xattr_ref(c, ref);
-                               rc = 0;
+                               ref->ino = ic->ino;
+                               ref->xid = xd->xid;
+                               ref->xseqno |= XREF_DELETE_MARKER;
+                               rc = save_xattr_ref(c, ref);
+                               if (!rc) {
+                                       *pref = ref->next;
+                                       spin_lock(&c->erase_completion_lock);
+                                       ref->next = c->xref_dead_list;
+                                       c->xref_dead_list = ref;
+                                       spin_unlock(&c->erase_completion_lock);
+                                       if (atomic_dec_and_test(&xd->refcnt))
+                                               delete_xattr_datum(c, xd);
+                               } else {
+                                       ref->ic = ic;
+                                       ref->xd = xd;
+                                       ref->xseqno &= ~XREF_DELETE_MARKER;
+                               }
                                goto out;
                        }
                        goto found;
@@ -1094,7 +1137,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
                goto out;
        }
        if (!buffer) {
-               rc = -EINVAL;
+               rc = -ENODATA;
                goto out;
        }
  found:
@@ -1110,16 +1153,14 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
        request = PAD(sizeof(struct jffs2_raw_xref));
        rc = jffs2_reserve_space(c, request, &length,
                                 ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE);
+       down_write(&c->xattr_sem);
        if (rc) {
                JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
-               down_write(&c->xattr_sem);
-               xd->refcnt--;
-               if (!xd->refcnt)
+               if (atomic_dec_and_test(&xd->refcnt))
                        delete_xattr_datum(c, xd);
                up_write(&c->xattr_sem);
                return rc;
        }
-       down_write(&c->xattr_sem);
        if (ref)
                *pref = ref->next;
        newref = create_xattr_ref(c, ic, xd);
@@ -1129,8 +1170,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
                        ic->xref = ref;
                }
                rc = PTR_ERR(newref);
-               xd->refcnt--;
-               if (!xd->refcnt)
+               if (atomic_dec_and_test(&xd->refcnt))
                        delete_xattr_datum(c, xd);
        } else if (ref) {
                delete_xattr_ref(c, ref);
@@ -1142,38 +1182,40 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
 }
 
 /* -------- garbage collector functions -------------
- * jffs2_garbage_collect_xattr_datum(c, xd)
+ * jffs2_garbage_collect_xattr_datum(c, xd, raw)
  *   is used to move xdatum into new node.
- * jffs2_garbage_collect_xattr_ref(c, ref)
+ * jffs2_garbage_collect_xattr_ref(c, ref, raw)
  *   is used to move xref into new node.
  * jffs2_verify_xattr(c)
  *   is used to call do_verify_xattr_datum() before garbage collecting.
+ * jffs2_release_xattr_datum(c, xd)
+ *   is used to release an in-memory object of xdatum.
+ * jffs2_release_xattr_ref(c, ref)
+ *   is used to release an in-memory object of xref.
  * -------------------------------------------------- */
-int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd,
+                                     struct jffs2_raw_node_ref *raw)
 {
        uint32_t totlen, length, old_ofs;
-       int rc = -EINVAL;
+       int rc = 0;
 
        down_write(&c->xattr_sem);
-       BUG_ON(!xd->node);
-
-       old_ofs = ref_offset(xd->node);
-       totlen = ref_totlen(c, c->gcblock, xd->node);
-       if (totlen < sizeof(struct jffs2_raw_xattr))
+       if (xd->node != raw)
+               goto out;
+       if (xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID))
                goto out;
 
-       if (!xd->xname) {
-               rc = load_xattr_datum(c, xd);
-               if (unlikely(rc > 0)) {
-                       delete_xattr_datum_node(c, xd);
-                       rc = 0;
-                       goto out;
-               } else if (unlikely(rc < 0))
-                       goto out;
+       rc = load_xattr_datum(c, xd);
+       if (unlikely(rc)) {
+               rc = (rc > 0) ? 0 : rc;
+               goto out;
        }
+       old_ofs = ref_offset(xd->node);
+       totlen = PAD(sizeof(struct jffs2_raw_xattr)
+                       + xd->name_len + 1 + xd->value_len);
        rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE);
-       if (rc || length < totlen) {
-               JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, totlen);
+       if (rc) {
+               JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen);
                rc = rc ? rc : -EBADFD;
                goto out;
        }
@@ -1182,27 +1224,32 @@ int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xatt
                dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n",
                          xd->xid, xd->version, old_ofs, ref_offset(xd->node));
  out:
+       if (!rc)
+               jffs2_mark_node_obsolete(c, raw);
        up_write(&c->xattr_sem);
        return rc;
 }
 
-
-int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref,
+                                   struct jffs2_raw_node_ref *raw)
 {
        uint32_t totlen, length, old_ofs;
-       int rc = -EINVAL;
+       int rc = 0;
 
        down_write(&c->xattr_sem);
        BUG_ON(!ref->node);
 
+       if (ref->node != raw)
+               goto out;
+       if (is_xattr_ref_dead(ref) && (raw->next_in_ino == (void *)ref))
+               goto out;
+
        old_ofs = ref_offset(ref->node);
        totlen = ref_totlen(c, c->gcblock, ref->node);
-       if (totlen != sizeof(struct jffs2_raw_xref))
-               goto out;
 
        rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XREF_SIZE);
-       if (rc || length < totlen) {
-               JFFS2_WARNING("%s: jffs2_reserve_space() = %d, request = %u\n",
+       if (rc) {
+               JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n",
                              __FUNCTION__, rc, totlen);
                rc = rc ? rc : -EBADFD;
                goto out;
@@ -1212,6 +1259,8 @@ int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_
                dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n",
                          ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node));
  out:
+       if (!rc)
+               jffs2_mark_node_obsolete(c, raw);
        up_write(&c->xattr_sem);
        return rc;
 }
@@ -1219,20 +1268,59 @@ int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_
 int jffs2_verify_xattr(struct jffs2_sb_info *c)
 {
        struct jffs2_xattr_datum *xd, *_xd;
+       struct jffs2_eraseblock *jeb;
+       struct jffs2_raw_node_ref *raw;
+       uint32_t totlen;
        int rc;
 
        down_write(&c->xattr_sem);
        list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) {
                rc = do_verify_xattr_datum(c, xd);
-               if (rc == 0) {
-                       list_del_init(&xd->xindex);
-                       break;
-               } else if (rc > 0) {
-                       list_del_init(&xd->xindex);
-                       delete_xattr_datum_node(c, xd);
+               if (rc < 0)
+                       continue;
+               list_del_init(&xd->xindex);
+               spin_lock(&c->erase_completion_lock);
+               for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
+                       if (ref_flags(raw) != REF_UNCHECKED)
+                               continue;
+                       jeb = &c->blocks[ref_offset(raw) / c->sector_size];
+                       totlen = PAD(ref_totlen(c, jeb, raw));
+                       c->unchecked_size -= totlen; c->used_size += totlen;
+                       jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+                       raw->flash_offset = ref_offset(raw)
+                               | ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL);
                }
+               if (xd->flags & JFFS2_XFLAGS_DEAD)
+                       list_add(&xd->xindex, &c->xattr_dead_list);
+               spin_unlock(&c->erase_completion_lock);
        }
        up_write(&c->xattr_sem);
-
        return list_empty(&c->xattr_unchecked) ? 1 : 0;
 }
+
+void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+       /* must be called under spin_lock(&c->erase_completion_lock) */
+       if (atomic_read(&xd->refcnt) || xd->node != (void *)xd)
+               return;
+
+       list_del(&xd->xindex);
+       jffs2_free_xattr_datum(xd);
+}
+
+void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+{
+       /* must be called under spin_lock(&c->erase_completion_lock) */
+       struct jffs2_xattr_ref *tmp, **ptmp;
+
+       if (ref->node != (void *)ref)
+               return;
+
+       for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) {
+               if (ref == tmp) {
+                       *ptmp = tmp->next;
+                       break;
+               }
+       }
+       jffs2_free_xattr_ref(ref);
+}
index 2c199856c58256b4726649b80d56a5bf975ae54e..06a5c69dcf8b1052d3dd8177d19a90198b9e284c 100644 (file)
@@ -16,6 +16,8 @@
 
 #define JFFS2_XFLAGS_HOT       (0x01)  /* This datum is HOT */
 #define JFFS2_XFLAGS_BIND      (0x02)  /* This datum is not reclaimed */
+#define JFFS2_XFLAGS_DEAD      (0x40)  /* This datum is already dead */
+#define JFFS2_XFLAGS_INVALID   (0x80)  /* This datum contains crc error */
 
 struct jffs2_xattr_datum
 {
@@ -23,10 +25,10 @@ struct jffs2_xattr_datum
        struct jffs2_raw_node_ref *node;
        uint8_t class;
        uint8_t flags;
-       uint16_t xprefix;                       /* see JFFS2_XATTR_PREFIX_* */
+       uint16_t xprefix;               /* see JFFS2_XATTR_PREFIX_* */
 
        struct list_head xindex;        /* chained from c->xattrindex[n] */
-       uint32_t refcnt;                /* # of xattr_ref refers this */
+       atomic_t refcnt;                /* # of xattr_ref refers this */
        uint32_t xid;
        uint32_t version;
 
@@ -47,6 +49,7 @@ struct jffs2_xattr_ref
        uint8_t flags;          /* Currently unused */
        u16 unused;
 
+       uint32_t xseqno;
        union {
                struct jffs2_inode_cache *ic;   /* reference to jffs2_inode_cache */
                uint32_t ino;                   /* only used in scanning/building  */
@@ -58,6 +61,12 @@ struct jffs2_xattr_ref
        struct jffs2_xattr_ref *next;           /* chained from ic->xref_list */
 };
 
+#define XREF_DELETE_MARKER     (0x00000001)
+static inline int is_xattr_ref_dead(struct jffs2_xattr_ref *ref)
+{
+       return ((ref->xseqno & XREF_DELETE_MARKER) != 0);
+}
+
 #ifdef CONFIG_JFFS2_FS_XATTR
 
 extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c);
@@ -70,9 +79,13 @@ extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c
 extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
 extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
 
-extern int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd);
-extern int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref);
+extern int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd,
+                                            struct jffs2_raw_node_ref *raw);
+extern int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref,
+                                          struct jffs2_raw_node_ref *raw);
 extern int jffs2_verify_xattr(struct jffs2_sb_info *c);
+extern void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd);
+extern void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref);
 
 extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
                             char *buffer, size_t size);
index 04eb78f1252e6b70f0383d63dbb2369dd5ca70f6..43e3f566aad65fb26a4dcf92845675d561746601 100644 (file)
@@ -305,7 +305,7 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb,
                                offset, nr_segs, jfs_get_block, NULL);
 }
 
-struct address_space_operations jfs_aops = {
+const struct address_space_operations jfs_aops = {
        .readpage       = jfs_readpage,
        .readpages      = jfs_readpages,
        .writepage      = jfs_writepage,
index c300726744641869b6e4f87794b2ece81d9b8280..b5c7da6190dc0ac2364536650923941b8fa43ac8 100644 (file)
@@ -33,7 +33,7 @@ extern void jfs_free_zero_link(struct inode *);
 extern struct dentry *jfs_get_parent(struct dentry *dentry);
 extern void jfs_set_inode_flags(struct inode *);
 
-extern struct address_space_operations jfs_aops;
+extern const struct address_space_operations jfs_aops;
 extern struct inode_operations jfs_dir_inode_operations;
 extern const struct file_operations jfs_dir_operations;
 extern struct inode_operations jfs_file_inode_operations;
index 7f6e88039700c085b09188b8ad350aaecc5b6733..e1e0a6e6ebdfb8d0e1c591a124a249e908fb2174 100644 (file)
@@ -577,7 +577,7 @@ static void metapage_invalidatepage(struct page *page, unsigned long offset)
        metapage_releasepage(page, 0);
 }
 
-struct address_space_operations jfs_metapage_aops = {
+const struct address_space_operations jfs_metapage_aops = {
        .readpage       = metapage_readpage,
        .writepage      = metapage_writepage,
        .sync_page      = block_sync_page,
index f0b7d3282b07397f49d61d65448d1778caf4173b..d17a3290f5aab901253c0f2d43b136a237dc893d 100644 (file)
@@ -139,7 +139,7 @@ static inline void metapage_homeok(struct metapage *mp)
        put_metapage(mp);
 }
 
-extern struct address_space_operations jfs_metapage_aops;
+extern const struct address_space_operations jfs_metapage_aops;
 
 /*
  * This routines invalidate all pages for an extent.
index a6fb509b7341153e729112c8d28fadca1fae2dfd..9ea91c5eeb7b27af1cd054c1887d514dc63db1f2 100644 (file)
@@ -335,7 +335,7 @@ static sector_t minix_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,minix_get_block);
 }
-static struct address_space_operations minix_aops = {
+static const struct address_space_operations minix_aops = {
        .readpage = minix_readpage,
        .writepage = minix_writepage,
        .sync_page = block_sync_page,
index 90d2ea28f333dfef1695c1a4a228934455383618..6c51c1198464efff9de569e5c98228b93206cf94 100644 (file)
@@ -105,7 +105,7 @@ static struct super_operations ncp_sops =
 
 extern struct dentry_operations ncp_root_dentry_operations;
 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
-extern struct address_space_operations ncp_symlink_aops;
+extern const struct address_space_operations ncp_symlink_aops;
 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
 #endif
 
index e935f1b34bc2935e589979ee69c32a2fada36863..f76b1392a012cbc291de7284437d862dc0c7a253 100644 (file)
@@ -99,7 +99,7 @@ fail:
 /*
  * symlinks can't do much...
  */
-struct address_space_operations ncp_symlink_aops = {
+const struct address_space_operations ncp_symlink_aops = {
        .readpage       = ncp_symlink_readpage,
 };
        
index 402005c35ab3fecd963329ff42be0b111f278381..8ca9707be6c9d06f28a843fbe6282afd1d405e77 100644 (file)
@@ -909,7 +909,7 @@ int __init nfs_init_directcache(void)
  * nfs_destroy_directcache - destroy the slab cache for nfs_direct_req structures
  *
  */
-void __exit nfs_destroy_directcache(void)
+void nfs_destroy_directcache(void)
 {
        if (kmem_cache_destroy(nfs_direct_cachep))
                printk(KERN_INFO "nfs_direct_cache: not all structures were freed\n");
index add289138836d9cab60a7687f79ac40f09af19f6..cc2b874ad5a4c38f4c63c0fe4b24028bbec6b030 100644 (file)
@@ -315,7 +315,7 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
        return !nfs_wb_page(page->mapping->host, page);
 }
 
-struct address_space_operations nfs_file_aops = {
+const struct address_space_operations nfs_file_aops = {
        .readpage = nfs_readpage,
        .readpages = nfs_readpages,
        .set_page_dirty = __set_page_dirty_nobuffers,
index 51bc88b662feabeb54f0873c1876296adabc0b25..c5b916605fb012b856bdee1c5cc8c8b4d9a8c81a 100644 (file)
@@ -1132,7 +1132,7 @@ static int __init nfs_init_inodecache(void)
        return 0;
 }
 
-static void __exit nfs_destroy_inodecache(void)
+static void nfs_destroy_inodecache(void)
 {
        if (kmem_cache_destroy(nfs_inode_cachep))
                printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");
index bd2815e2dec1b924bf52bb803f490066c76b2e94..4fe51c1292bb763918cd885c0df1ba093fccd80e 100644 (file)
@@ -31,15 +31,15 @@ extern struct svc_version nfs4_callback_version1;
 
 /* pagelist.c */
 extern int __init nfs_init_nfspagecache(void);
-extern void __exit nfs_destroy_nfspagecache(void);
+extern void nfs_destroy_nfspagecache(void);
 extern int __init nfs_init_readpagecache(void);
-extern void __exit nfs_destroy_readpagecache(void);
+extern void nfs_destroy_readpagecache(void);
 extern int __init nfs_init_writepagecache(void);
-extern void __exit nfs_destroy_writepagecache(void);
+extern void nfs_destroy_writepagecache(void);
 
 #ifdef CONFIG_NFS_DIRECTIO
 extern int __init nfs_init_directcache(void);
-extern void __exit nfs_destroy_directcache(void);
+extern void nfs_destroy_directcache(void);
 #else
 #define nfs_init_directcache() (0)
 #define nfs_destroy_directcache() do {} while(0)
index ef9429643ebcc8e231268e58551cbf899df0336c..d89f6fb3b3a3517fea9679caec85982584ad7d81 100644 (file)
@@ -390,7 +390,7 @@ int __init nfs_init_nfspagecache(void)
        return 0;
 }
 
-void __exit nfs_destroy_nfspagecache(void)
+void nfs_destroy_nfspagecache(void)
 {
        if (kmem_cache_destroy(nfs_page_cachep))
                printk(KERN_INFO "nfs_page: not all structures were freed\n");
index 41c2ffee24f566dabf38f271e6ecdfa3fa3ea0d1..32cf3773af0cdc0a21b41363e6ddc34c7a40bff2 100644 (file)
@@ -711,7 +711,7 @@ int __init nfs_init_readpagecache(void)
        return 0;
 }
 
-void __exit nfs_destroy_readpagecache(void)
+void nfs_destroy_readpagecache(void)
 {
        mempool_destroy(nfs_rdata_mempool);
        if (kmem_cache_destroy(nfs_rdata_cachep))
index b383fdd3a15c1a5b6b621415b46ffe390a3294d2..8fccb9cb173ba9588c6f8946ba69cc67485659c2 100644 (file)
@@ -1551,7 +1551,7 @@ int __init nfs_init_writepagecache(void)
        return 0;
 }
 
-void __exit nfs_destroy_writepagecache(void)
+void nfs_destroy_writepagecache(void)
 {
        mempool_destroy(nfs_commit_mempool);
        mempool_destroy(nfs_wdata_mempool);
index 1630b5670dc2652ff36b9bee862f68a386904933..7c7d01672d35a4dc47bbd5ca5d059adcdc1c6598 100644 (file)
@@ -123,7 +123,7 @@ static void release_stateid(struct nfs4_stateid *stp, int flags);
  */
 
 /* recall_lock protects the del_recall_lru */
-static spinlock_t recall_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(recall_lock);
 static struct list_head del_recall_lru;
 
 static void
index 580412d330cb9187035d037d9259e52222f0f87f..bc579bfdfbd8ff0c09c701a849b8b61c362b0fa0 100644 (file)
@@ -1544,7 +1544,7 @@ err_out:
 /**
  * ntfs_aops - general address space operations for inodes and attributes
  */
-struct address_space_operations ntfs_aops = {
+const struct address_space_operations ntfs_aops = {
        .readpage       = ntfs_readpage,        /* Fill page with data. */
        .sync_page      = block_sync_page,      /* Currently, just unplugs the
                                                   disk request queue. */
@@ -1560,7 +1560,7 @@ struct address_space_operations ntfs_aops = {
  * ntfs_mst_aops - general address space operations for mst protecteed inodes
  *                and attributes
  */
-struct address_space_operations ntfs_mst_aops = {
+const struct address_space_operations ntfs_mst_aops = {
        .readpage       = ntfs_readpage,        /* Fill page with data. */
        .sync_page      = block_sync_page,      /* Currently, just unplugs the
                                                   disk request queue. */
index bf7b3d7c09303a17de113173b80b2b8890d97ecb..ddd3d503097c081e42176abb5fd494864fcf56c4 100644 (file)
@@ -57,8 +57,8 @@ extern struct kmem_cache *ntfs_attr_ctx_cache;
 extern struct kmem_cache *ntfs_index_ctx_cache;
 
 /* The various operations structs defined throughout the driver files. */
-extern struct address_space_operations ntfs_aops;
-extern struct address_space_operations ntfs_mst_aops;
+extern const struct address_space_operations ntfs_aops;
+extern const struct address_space_operations ntfs_mst_aops;
 
 extern const struct  file_operations ntfs_file_ops;
 extern struct inode_operations ntfs_file_inode_ops;
index 47152bf9a7f26cdfb82cd02240e5546ba3e47485..cca71317b6d6144e5bd381bacb9149a6f9fddde5 100644 (file)
@@ -666,7 +666,7 @@ out:
        return ret;
 }
 
-struct address_space_operations ocfs2_aops = {
+const struct address_space_operations ocfs2_aops = {
        .readpage       = ocfs2_readpage,
        .writepage      = ocfs2_writepage,
        .prepare_write  = ocfs2_prepare_write,
index 21f38accd0399dd26f6fa1da70af16209c01469e..1d26cfcd9f8406a531ab8acd61a5c813633658a8 100644 (file)
@@ -54,7 +54,7 @@ static DECLARE_RWSEM(o2hb_callback_sem);
  * multiple hb threads are watching multiple regions.  A node is live
  * whenever any of the threads sees activity from the node in its region.
  */
-static spinlock_t o2hb_live_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(o2hb_live_lock);
 static struct list_head o2hb_live_slots[O2NM_MAX_NODES];
 static unsigned long o2hb_live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
 static LIST_HEAD(o2hb_node_events);
index 0f60cc0d3985d9e80596e3f63b7059cb594d7d97..1591eb37a72366dc2e4ecbac76128e2d5b7e0d26 100644 (file)
            ##args);                                                    \
 } while (0)
 
-static rwlock_t o2net_handler_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(o2net_handler_lock);
 static struct rb_root o2net_handler_tree = RB_ROOT;
 
 static struct o2net_node o2net_nodes[O2NM_MAX_NODES];
index ba27c5c5e95939192f0bacfe5bfeb7c2776d67a3..b8c23f7ba67e1caf791af2e8f4f28e8f0c6e6413 100644 (file)
@@ -88,7 +88,7 @@ out_free:
  *
  */
 
-spinlock_t dlm_domain_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(dlm_domain_lock);
 LIST_HEAD(dlm_domains);
 static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events);
 
index d6f89577e25f1b0ac55f5ac8e931013ff2b460ee..5ca57ec650c77657c76e82e66f83dea2180da01a 100644 (file)
@@ -53,7 +53,7 @@
 #define MLOG_MASK_PREFIX ML_DLM
 #include "cluster/masklog.h"
 
-static spinlock_t dlm_cookie_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(dlm_cookie_lock);
 static u64 dlm_next_cookie = 1;
 
 static enum dlm_status dlm_send_remote_lock_request(struct dlm_ctxt *dlm,
index da399013516ffe5947ac111f09b963e8c5a9c99b..29b2845f370d85b1a4b642af386553cd6178f708 100644 (file)
@@ -98,8 +98,8 @@ static void dlm_mig_lockres_worker(struct dlm_work_item *item, void *data);
 
 static u64 dlm_get_next_mig_cookie(void);
 
-static spinlock_t dlm_reco_state_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t dlm_mig_cookie_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(dlm_reco_state_lock);
+static DEFINE_SPINLOCK(dlm_mig_cookie_lock);
 static u64 dlm_mig_cookie = 1;
 
 static u64 dlm_get_next_mig_cookie(void)
index 64cd52860c876943d3a51a373f8a74df9f7067f5..4acd37286bdd7cb4b0807da5b338a9f6753ffb99 100644 (file)
@@ -242,7 +242,7 @@ static void ocfs2_build_lock_name(enum ocfs2_lock_type type,
        mlog_exit_void();
 }
 
-static spinlock_t ocfs2_dlm_tracking_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ocfs2_dlm_tracking_lock);
 
 static void ocfs2_add_lockres_tracking(struct ocfs2_lock_res *res,
                                       struct ocfs2_dlm_debug *dlm_debug)
index 84c5079612870bae7ba80aa5e8831a63564687d9..35140f6cf840eedbfde59f23515e8342f9c9ab7a 100644 (file)
@@ -114,7 +114,7 @@ static inline struct ocfs2_inode_info *OCFS2_I(struct inode *inode)
 
 extern kmem_cache_t *ocfs2_inode_cache;
 
-extern struct address_space_operations ocfs2_aops;
+extern const struct address_space_operations ocfs2_aops;
 
 struct buffer_head *ocfs2_bread(struct inode *inode, int block,
                                int *err, int reada);
index 3fe8781c22cb68fedf6c5d8189c9aab3f88fa0d1..910a601b2e9820cf4986e3e620faa534277cf072 100644 (file)
@@ -49,7 +49,7 @@
 
 #include "buffer_head_io.h"
 
-spinlock_t trans_inc_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(trans_inc_lock);
 
 static int ocfs2_force_read_journal(struct inode *inode);
 static int ocfs2_recover_node(struct ocfs2_super *osb,
index ee42765a8553e9c5ed51e47805f9bd1440679399..cf70fe2075b8f58e1a4109e7872da1cc7c246c21 100644 (file)
@@ -988,9 +988,7 @@ int ocfs2_request_mount_vote(struct ocfs2_super *osb)
        }
 
 bail:
-       if (request)
-               kfree(request);
-
+       kfree(request);
        return status;
 }
 
@@ -1021,9 +1019,7 @@ int ocfs2_request_umount_vote(struct ocfs2_super *osb)
        }
 
 bail:
-       if (request)
-               kfree(request);
-
+       kfree(request);
        return status;
 }
 
index 42c7d3878ed08272f5d2341fe93d2182c2257665..d713ce6b3e12935891bda7e21d301ec3d53038f8 100644 (file)
@@ -4,7 +4,6 @@
 
 obj-y := check.o
 
-obj-$(CONFIG_DEVFS_FS) += devfs.o
 obj-$(CONFIG_ACORN_PARTITION) += acorn.o
 obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
 obj-$(CONFIG_ATARI_PARTITION) += atari.o
index 2ef313a96b665a09b3e076a6259d131459fc1900..839634026eb5206e934e34a78ec5a5998248569e 100644 (file)
 #include <linux/fs.h>
 #include <linux/kmod.h>
 #include <linux/ctype.h>
-#include <linux/devfs_fs_kernel.h>
 
 #include "check.h"
-#include "devfs.h"
 
 #include "acorn.h"
 #include "amiga.h"
@@ -161,18 +159,11 @@ check_partition(struct gendisk *hd, struct block_device *bdev)
        if (!state)
                return NULL;
 
-#ifdef CONFIG_DEVFS_FS
-       if (hd->devfs_name[0] != '\0') {
-               printk(KERN_INFO " /dev/%s:", hd->devfs_name);
+       disk_name(hd, 0, state->name);
+       printk(KERN_INFO " %s:", state->name);
+       if (isdigit(state->name[strlen(state->name)-1]))
                sprintf(state->name, "p");
-       }
-#endif
-       else {
-               disk_name(hd, 0, state->name);
-               printk(KERN_INFO " %s:", state->name);
-               if (isdigit(state->name[strlen(state->name)-1]))
-                       sprintf(state->name, "p");
-       }
+
        state->limit = hd->minors;
        i = res = 0;
        while (!res && check_part[i]) {
@@ -328,7 +319,6 @@ void delete_partition(struct gendisk *disk, int part)
        p->nr_sects = 0;
        p->ios[0] = p->ios[1] = 0;
        p->sectors[0] = p->sectors[1] = 0;
-       devfs_remove("%s/part%d", disk->devfs_name, part);
        sysfs_remove_link(&p->kobj, "subsystem");
        if (p->holder_dir)
                kobject_unregister(p->holder_dir);
@@ -350,10 +340,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
        p->nr_sects = len;
        p->partno = part;
 
-       devfs_mk_bdev(MKDEV(disk->major, disk->first_minor + part),
-                       S_IFBLK|S_IRUSR|S_IWUSR,
-                       "%s/part%d", disk->devfs_name, part);
-
        if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1]))
                snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part);
        else
@@ -423,14 +409,8 @@ void register_disk(struct gendisk *disk)
        disk_sysfs_add_subdirs(disk);
 
        /* No minors to use for partitions */
-       if (disk->minors == 1) {
-               if (disk->devfs_name[0] != '\0')
-                       devfs_add_disk(disk);
+       if (disk->minors == 1)
                goto exit;
-       }
-
-       /* always add handle for the whole disk */
-       devfs_add_partitioned(disk);
 
        /* No such device (e.g., media were just removed) */
        if (!get_capacity(disk))
@@ -538,8 +518,6 @@ void del_gendisk(struct gendisk *disk)
        disk_stat_set_all(disk, 0);
        disk->stamp = 0;
 
-       devfs_remove_disk(disk);
-
        kobject_uevent(&disk->kobj, KOBJ_REMOVE);
        if (disk->holder_dir)
                kobject_unregister(disk->holder_dir);
diff --git a/fs/partitions/devfs.c b/fs/partitions/devfs.c
deleted file mode 100644 (file)
index 3f0a780..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * This tries to keep block devices away from devfs as much as possible.
- */
-#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/genhd.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-
-
-struct unique_numspace {
-       u32               num_free;          /*  Num free in bits       */
-       u32               length;            /*  Array length in bytes  */
-       unsigned long     *bits;
-       struct semaphore  mutex;
-};
-
-static DEFINE_MUTEX(numspace_mutex);
-
-static int expand_numspace(struct unique_numspace *s)
-{
-       u32 length;
-       void *bits;
-
-       if (s->length < 16)
-               length = 16;
-       else
-               length = s->length << 1;
-
-       bits = vmalloc(length);
-       if (!bits)
-               return -ENOMEM;
-       if (s->bits) {
-               memcpy(bits, s->bits, s->length);
-               vfree(s->bits);
-       }
-               
-       s->num_free = (length - s->length) << 3;
-       s->bits = bits;
-       memset(bits + s->length, 0, length - s->length);
-       s->length = length;
-
-       return 0;
-}
-
-static int alloc_unique_number(struct unique_numspace *s)
-{
-       int rval = 0;
-
-       mutex_lock(&numspace_mutex);
-       if (s->num_free < 1)
-               rval = expand_numspace(s);
-       if (!rval) {
-               rval = find_first_zero_bit(s->bits, s->length << 3);
-               --s->num_free;
-               __set_bit(rval, s->bits);
-       }
-       mutex_unlock(&numspace_mutex);
-
-       return rval;
-}
-
-static void dealloc_unique_number(struct unique_numspace *s, int number)
-{
-       int old_val;
-
-       if (number >= 0) {
-               mutex_lock(&numspace_mutex);
-               old_val = __test_and_clear_bit(number, s->bits);
-               if (old_val)
-                       ++s->num_free;
-               mutex_unlock(&numspace_mutex);
-       }
-}
-
-static struct unique_numspace disc_numspace;
-static struct unique_numspace cdrom_numspace;
-
-void devfs_add_partitioned(struct gendisk *disk)
-{
-       char dirname[64], symlink[16];
-
-       devfs_mk_dir(disk->devfs_name);
-       devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
-                       S_IFBLK|S_IRUSR|S_IWUSR,
-                       "%s/disc", disk->devfs_name);
-
-       disk->number = alloc_unique_number(&disc_numspace);
-
-       sprintf(symlink, "discs/disc%d", disk->number);
-       sprintf(dirname, "../%s", disk->devfs_name);
-       devfs_mk_symlink(symlink, dirname);
-
-}
-
-void devfs_add_disk(struct gendisk *disk)
-{
-       devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
-                       (disk->flags & GENHD_FL_CD) ?
-                               S_IFBLK|S_IRUGO|S_IWUGO :
-                               S_IFBLK|S_IRUSR|S_IWUSR,
-                       "%s", disk->devfs_name);
-
-       if (disk->flags & GENHD_FL_CD) {
-               char dirname[64], symlink[16];
-
-               disk->number = alloc_unique_number(&cdrom_numspace);
-
-               sprintf(symlink, "cdroms/cdrom%d", disk->number);
-               sprintf(dirname, "../%s", disk->devfs_name);
-               devfs_mk_symlink(symlink, dirname);
-       }
-}
-
-void devfs_remove_disk(struct gendisk *disk)
-{
-       if (disk->minors != 1) {
-               devfs_remove("discs/disc%d", disk->number);
-               dealloc_unique_number(&disc_numspace, disk->number);
-               devfs_remove("%s/disc", disk->devfs_name);
-       }
-       if (disk->flags & GENHD_FL_CD) {
-               devfs_remove("cdroms/cdrom%d", disk->number);
-               dealloc_unique_number(&cdrom_numspace, disk->number);
-       }
-       devfs_remove(disk->devfs_name);
-}
-
-
diff --git a/fs/partitions/devfs.h b/fs/partitions/devfs.h
deleted file mode 100644 (file)
index 176118b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-
-#ifdef CONFIG_DEVFS_FS
-void devfs_add_disk(struct gendisk *dev);
-void devfs_add_partitioned(struct gendisk *dev);
-void devfs_remove_disk(struct gendisk *dev);
-#else
-# define devfs_add_disk(disk)                  do { } while (0)
-# define devfs_add_partitioned(disk)           do { } while (0)
-# define devfs_remove_disk(disk)               do { } while (0)
-#endif
index 0137ec4c1368888d906d6eb543a238e5dca18236..0a163a4f7764059f7401c8b43cae42ca9c2bef43 100644 (file)
@@ -122,6 +122,11 @@ struct mem_size_stats
        unsigned long private_dirty;
 };
 
+__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma)
+{
+       return NULL;
+}
+
 static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
 {
        struct proc_maps_private *priv = m->private;
@@ -158,22 +163,23 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
                pad_len_spaces(m, len);
                seq_path(m, file->f_vfsmnt, file->f_dentry, "\n");
        } else {
-               if (mm) {
-                       if (vma->vm_start <= mm->start_brk &&
+               const char *name = arch_vma_name(vma);
+               if (!name) {
+                       if (mm) {
+                               if (vma->vm_start <= mm->start_brk &&
                                                vma->vm_end >= mm->brk) {
-                               pad_len_spaces(m, len);
-                               seq_puts(m, "[heap]");
-                       } else {
-                               if (vma->vm_start <= mm->start_stack &&
-                                       vma->vm_end >= mm->start_stack) {
-
-                                       pad_len_spaces(m, len);
-                                       seq_puts(m, "[stack]");
+                                       name = "[heap]";
+                               } else if (vma->vm_start <= mm->start_stack &&
+                                          vma->vm_end >= mm->start_stack) {
+                                       name = "[stack]";
                                }
+                       } else {
+                               name = "[vdso]";
                        }
-               } else {
+               }
+               if (name) {
                        pad_len_spaces(m, len);
-                       seq_puts(m, "[vdso]");
+                       seq_puts(m, name);
                }
        }
        seq_putc(m, '\n');
index 2f24c46f72a1bdc19b21062c78cfb07838a67151..8bc182a88748a91abbdc7b46032d81ac5c9ad9fa 100644 (file)
@@ -450,7 +450,7 @@ static sector_t qnx4_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,qnx4_get_block);
 }
-static struct address_space_operations qnx4_aops = {
+static const struct address_space_operations qnx4_aops = {
        .readpage       = qnx4_readpage,
        .writepage      = qnx4_writepage,
        .sync_page      = block_sync_page,
index 00a933eb820c27127cc330adbca12e6518deb4d8..86f14cacf64120569f2fd0ad8e6ee573de98eb4e 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <linux/fs.h>
 
-struct address_space_operations ramfs_aops = {
+const struct address_space_operations ramfs_aops = {
        .readpage       = simple_readpage,
        .prepare_write  = simple_prepare_write,
        .commit_write   = simple_commit_write
index f443a84b98a5a300b21fbf298f7aa2587e6e83eb..99fffc9e1bfd6ebf4959ac6415d8e80e19deff56 100644 (file)
@@ -27,7 +27,7 @@
 
 static int ramfs_nommu_setattr(struct dentry *, struct iattr *);
 
-struct address_space_operations ramfs_aops = {
+const struct address_space_operations ramfs_aops = {
        .readpage               = simple_readpage,
        .prepare_write          = simple_prepare_write,
        .commit_write           = simple_commit_write
index 313237631b49dda2c66145fcc0bab146cc5472aa..c2bb58e74653351797d75c654b855b1fa72b4ed5 100644 (file)
@@ -10,6 +10,6 @@
  */
 
 
-extern struct address_space_operations ramfs_aops;
+extern const struct address_space_operations ramfs_aops;
 extern const struct file_operations ramfs_file_operations;
 extern struct inode_operations ramfs_file_inode_operations;
index 9857e50f85e723c00637ce6e26604cf8f07b6e7b..a24858a632fab85ef57f3ebf291a8a2235f2f182 100644 (file)
@@ -2996,7 +2996,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
        return error;
 }
 
-struct address_space_operations reiserfs_address_space_operations = {
+const struct address_space_operations reiserfs_address_space_operations = {
        .writepage = reiserfs_writepage,
        .readpage = reiserfs_readpage,
        .readpages = reiserfs_readpages,
index 283fbc6b8eea3776a685135d899ffc7daddaac3e..22eed61ebf693dd70c51c1bebe1938d2ffb0f528 100644 (file)
@@ -459,7 +459,7 @@ err_out:
 
 /* Mapping from our types to the kernel */
 
-static struct address_space_operations romfs_aops = {
+static const struct address_space_operations romfs_aops = {
        .readpage = romfs_readpage
 };
 
index ed9a24d19d7d312ed5336c7d0873a059e3c804fb..dae67048baba345fcbd6358e4a84fd890f834633 100644 (file)
@@ -306,7 +306,7 @@ static int smb_commit_write(struct file *file, struct page *page,
        return status;
 }
 
-struct address_space_operations smb_file_aops = {
+const struct address_space_operations smb_file_aops = {
        .readpage = smb_readpage,
        .writepage = smb_writepage,
        .prepare_write = smb_prepare_write,
index 972ed7dad388c3bc9c1075e36a61bced30ded427..34fb462b23795c63581648ab69149faaf7bedfd4 100644 (file)
@@ -63,7 +63,7 @@ extern int smb_revalidate_inode(struct dentry *dentry);
 extern int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
 extern int smb_notify_change(struct dentry *dentry, struct iattr *attr);
 /* file.c */
-extern struct address_space_operations smb_file_aops;
+extern const struct address_space_operations smb_file_aops;
 extern const struct file_operations smb_file_operations;
 extern struct inode_operations smb_file_inode_operations;
 /* ioctl.c */
index f0b347bd12ca52d6636b2cadae31a7f45f2067a7..5e0e31cc46f5e269ebb8ed5c2fddec10f240e512 100644 (file)
@@ -16,7 +16,7 @@
 
 extern struct super_block * sysfs_sb;
 
-static struct address_space_operations sysfs_aops = {
+static const struct address_space_operations sysfs_aops = {
        .readpage       = simple_readpage,
        .prepare_write  = simple_prepare_write,
        .commit_write   = simple_commit_write
index 86f5f8d43d0f6debbfcd26ba292140cfe4fed0d9..f2bcccd1d6fcf42fb9ac5db739eaf33d2ad43fc4 100644 (file)
@@ -465,7 +465,7 @@ static sector_t sysv_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,get_block);
 }
-struct address_space_operations sysv_aops = {
+const struct address_space_operations sysv_aops = {
        .readpage = sysv_readpage,
        .writepage = sysv_writepage,
        .sync_page = block_sync_page,
index 393a480e4deb0860190a1bda62d37178d2846d85..9dcc82120935baba74960a691fc0ef15d2b1009b 100644 (file)
@@ -161,7 +161,7 @@ extern struct inode_operations sysv_dir_inode_operations;
 extern struct inode_operations sysv_fast_symlink_inode_operations;
 extern const struct file_operations sysv_file_operations;
 extern const struct file_operations sysv_dir_operations;
-extern struct address_space_operations sysv_aops;
+extern const struct address_space_operations sysv_aops;
 extern struct super_operations sysv_sops;
 extern struct dentry_operations sysv_dentry_operations;
 
index e34b00e303f13ae9cdd75d35a3649b6346b5c027..a59e5f33daf6f7ed5225d8f85c349acbf29f05ab 100644 (file)
@@ -95,7 +95,7 @@ static int udf_adinicb_commit_write(struct file *file, struct page *page, unsign
        return 0;
 }
 
-struct address_space_operations udf_adinicb_aops = {
+const struct address_space_operations udf_adinicb_aops = {
        .readpage               = udf_adinicb_readpage,
        .writepage              = udf_adinicb_writepage,
        .sync_page              = block_sync_page,
index 2983afd5e7fd4932ca77cd24e95041f94b719062..605f5111b6d86a100430897877f170c2b59248e7 100644 (file)
@@ -132,7 +132,7 @@ static sector_t udf_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping,block,udf_get_block);
 }
 
-struct address_space_operations udf_aops = {
+const struct address_space_operations udf_aops = {
        .readpage               = udf_readpage,
        .writepage              = udf_writepage,
        .sync_page              = block_sync_page,
index 674bb40edc839475cb4bdf5f1fd3b789808ee144..ba068a7865630bb07a8f968a91d20c13245c143f 100644 (file)
@@ -113,6 +113,6 @@ out:
 /*
  * symlinks can't do much...
  */
-struct address_space_operations udf_symlink_aops = {
+const struct address_space_operations udf_symlink_aops = {
        .readpage               = udf_symlink_filler,
 };
index 023e19ba5a2ee8be3d2f4df434564aa70a5f1dc8..2f992387cc9ed0a9cba2bd64c704d2e175f78fe2 100644 (file)
@@ -47,9 +47,9 @@ extern struct inode_operations udf_dir_inode_operations;
 extern const struct file_operations udf_dir_operations;
 extern struct inode_operations udf_file_inode_operations;
 extern const struct file_operations udf_file_operations;
-extern struct address_space_operations udf_aops;
-extern struct address_space_operations udf_adinicb_aops;
-extern struct address_space_operations udf_symlink_aops;
+extern const struct address_space_operations udf_aops;
+extern const struct address_space_operations udf_adinicb_aops;
+extern const struct address_space_operations udf_symlink_aops;
 
 struct udf_fileident_bh
 {
index f2dbdf5a8769765d4ca175250e19e0659bb5f7c8..488b5ff48afb1330ca5f40360af42e25231637d3 100644 (file)
@@ -98,7 +98,9 @@ static u64 ufs_frag_map(struct inode *inode, sector_t frag)
        u64 temp = 0L;
 
        UFSD(": frag = %llu  depth = %d\n", (unsigned long long)frag, depth);
-       UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask);
+       UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",
+               uspi->s_fpbshift, uspi->s_apbmask,
+               (unsigned long long)mask);
 
        if (depth == 0)
                return 0;
@@ -429,7 +431,7 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head
        
        if (!create) {
                phys64 = ufs_frag_map(inode, fragment);
-               UFSD("phys64 = %llu \n",phys64);
+               UFSD("phys64 = %llu\n", (unsigned long long)phys64);
                if (phys64)
                        map_bh(bh_result, sb, phys64);
                return 0;
@@ -574,7 +576,7 @@ static sector_t ufs_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,ufs_getfrag_block);
 }
-struct address_space_operations ufs_aops = {
+const struct address_space_operations ufs_aops = {
        .readpage = ufs_readpage,
        .writepage = ufs_writepage,
        .sync_page = block_sync_page,
@@ -605,39 +607,12 @@ static void ufs_set_inode_ops(struct inode *inode)
                                   ufs_get_inode_dev(inode->i_sb, UFS_I(inode)));
 }
 
-void ufs_read_inode (struct inode * inode)
+static void ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode)
 {
        struct ufs_inode_info *ufsi = UFS_I(inode);
-       struct super_block * sb;
-       struct ufs_sb_private_info * uspi;
-       struct ufs_inode * ufs_inode;   
-       struct ufs2_inode *ufs2_inode;
-       struct buffer_head * bh;
+       struct super_block *sb = inode->i_sb;
        mode_t mode;
        unsigned i;
-       unsigned flags;
-       
-       UFSD("ENTER, ino %lu\n", inode->i_ino);
-       
-       sb = inode->i_sb;
-       uspi = UFS_SB(sb)->s_uspi;
-       flags = UFS_SB(sb)->s_flags;
-
-       if (inode->i_ino < UFS_ROOTINO || 
-           inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
-               ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino);
-               goto bad_inode;
-       }
-       
-       bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino));
-       if (!bh) {
-               ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
-               goto bad_inode;
-       }
-       if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
-               goto ufs2_inode;
-
-       ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino));
 
        /*
         * Copy data to the in-core inode.
@@ -661,14 +636,11 @@ void ufs_read_inode (struct inode * inode)
        inode->i_atime.tv_nsec = 0;
        inode->i_ctime.tv_nsec = 0;
        inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks);
-       inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat) */
-       inode->i_version++;
        ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags);
        ufsi->i_gen = fs32_to_cpu(sb, ufs_inode->ui_gen);
        ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
        ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
-       ufsi->i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
-       ufsi->i_dir_start_lookup = 0;
+
        
        if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
                for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
@@ -677,24 +649,16 @@ void ufs_read_inode (struct inode * inode)
                for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
                        ufsi->i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
        }
-       ufsi->i_osync = 0;
-
-       ufs_set_inode_ops(inode);
-
-       brelse (bh);
-
-       UFSD("EXIT\n");
-       return;
+}
 
-bad_inode:
-       make_bad_inode(inode);
-       return;
+static void ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode)
+{
+       struct ufs_inode_info *ufsi = UFS_I(inode);
+       struct super_block *sb = inode->i_sb;
+       mode_t mode;
+       unsigned i;
 
-ufs2_inode :
        UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino);
-
-       ufs2_inode = (struct ufs2_inode *)(bh->b_data + sizeof(struct ufs2_inode) * ufs_inotofsbo(inode->i_ino));
-
        /*
         * Copy data to the in-core inode.
         */
@@ -717,26 +681,64 @@ ufs2_inode :
        inode->i_atime.tv_nsec = 0;
        inode->i_ctime.tv_nsec = 0;
        inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks);
-       inode->i_blksize = PAGE_SIZE; /*This is the optimal IO size(for stat)*/
-
-       inode->i_version++;
        ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags);
        ufsi->i_gen = fs32_to_cpu(sb, ufs2_inode->ui_gen);
        /*
        ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
        ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
        */
-       ufsi->i_lastfrag= (inode->i_size + uspi->s_fsize- 1) >> uspi->s_fshift;
 
        if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
                for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
                        ufsi->i_u1.u2_i_data[i] =
                                ufs2_inode->ui_u2.ui_addr.ui_db[i];
-       }
-       else {
+       } else {
                for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
                        ufsi->i_u1.i_symlink[i] = ufs2_inode->ui_u2.ui_symlink[i];
        }
+}
+
+void ufs_read_inode(struct inode * inode)
+{
+       struct ufs_inode_info *ufsi = UFS_I(inode);
+       struct super_block * sb;
+       struct ufs_sb_private_info * uspi;
+       struct buffer_head * bh;
+
+       UFSD("ENTER, ino %lu\n", inode->i_ino);
+
+       sb = inode->i_sb;
+       uspi = UFS_SB(sb)->s_uspi;
+
+       if (inode->i_ino < UFS_ROOTINO ||
+           inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
+               ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n",
+                           inode->i_ino);
+               goto bad_inode;
+       }
+
+       bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino));
+       if (!bh) {
+               ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n",
+                           inode->i_ino);
+               goto bad_inode;
+       }
+       if ((UFS_SB(sb)->s_flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+               struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data;
+
+               ufs2_read_inode(inode,
+                               ufs2_inode + ufs_inotofsbo(inode->i_ino));
+       } else {
+               struct ufs_inode *ufs_inode = (struct ufs_inode *)bh->b_data;
+
+               ufs1_read_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino));
+       }
+
+       inode->i_blksize = PAGE_SIZE;/*This is the optimal IO size (for stat)*/
+       inode->i_version++;
+       ufsi->i_lastfrag =
+               (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
+       ufsi->i_dir_start_lookup = 0;
        ufsi->i_osync = 0;
 
        ufs_set_inode_ops(inode);
@@ -745,6 +747,9 @@ ufs2_inode :
 
        UFSD("EXIT\n");
        return;
+
+bad_inode:
+       make_bad_inode(inode);
 }
 
 static int ufs_update_inode(struct inode * inode, int do_sync)
index 3e807b828e221464131d088367496f86f54bb033..c40f81ba9b130426125228e5bfac38d7059bfd1e 100644 (file)
@@ -1454,7 +1454,7 @@ xfs_vm_invalidatepage(
        block_invalidatepage(page, offset);
 }
 
-struct address_space_operations xfs_address_space_operations = {
+const struct address_space_operations xfs_address_space_operations = {
        .readpage               = xfs_vm_readpage,
        .readpages              = xfs_vm_readpages,
        .writepage              = xfs_vm_writepage,
index 706d8c781b8a54b474f7a3d5ecb23a42bf8e8352..2244e516b66a339600830928682a7155df931639 100644 (file)
@@ -40,7 +40,7 @@ typedef struct xfs_ioend {
        struct work_struct      io_work;        /* xfsdatad work queue */
 } xfs_ioend_t;
 
-extern struct address_space_operations xfs_address_space_operations;
+extern const struct address_space_operations xfs_address_space_operations;
 extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int);
 
 #endif /* __XFS_AOPS_H__ */
index 26fed0756f0100b5c2e2aec31eb5e1f5853c9ed4..2af528dcfb0428ca93f2a5dced879e400682b876 100644 (file)
@@ -1520,7 +1520,7 @@ xfs_mapping_buftarg(
        struct backing_dev_info *bdi;
        struct inode            *inode;
        struct address_space    *mapping;
-       static struct address_space_operations mapping_aops = {
+       static const struct address_space_operations mapping_aops = {
                .sync_page = block_sync_page,
                .migratepage = fail_migrate_page,
        };
index 12810baeb5d4ad7e4c54c7690b08d2fa3fe9de1c..d9180020de6328fa8dbbeb17f68027805d368fae 100644 (file)
@@ -419,16 +419,15 @@ xfs_vn_link(
        int             error;
 
        ip = old_dentry->d_inode;       /* inode being linked to */
-       if (S_ISDIR(ip->i_mode))
-               return -EPERM;
-
        tdvp = vn_from_inode(dir);
        vp = vn_from_inode(ip);
 
+       VN_HOLD(vp);
        error = bhv_vop_link(tdvp, vp, dentry, NULL);
-       if (likely(!error)) {
+       if (unlikely(error)) {
+               VN_RELE(vp);
+       } else {
                VMODIFY(tdvp);
-               VN_HOLD(vp);
                xfs_validate_fields(ip, &vattr);
                d_instantiate(dentry, ip);
        }
index aa26ab906c88cda071d9a2ca54cc79ee2cea6317..028eb17ec2edd8b17e35b333e1b0692ba63414c7 100644 (file)
@@ -140,9 +140,7 @@ BUFFER_FNS(PrivateStart, unwritten);
 #define current_pid()          (current->pid)
 #define current_fsuid(cred)    (current->fsuid)
 #define current_fsgid(cred)    (current->fsgid)
-#define current_set_flags(f)   (current->flags |= (f))
 #define current_test_flags(f)  (current->flags & (f))
-#define current_clear_flags(f) (current->flags & ~(f))
 #define current_set_flags_nested(sp, f)                \
                (*(sp) = current->flags, current->flags |= (f))
 #define current_clear_flags_nested(sp, f)      \
index 35c6a01963a77c9c52af0ba70453926aab316f04..c42b3221b20cb95a0a1303b2d6c51a4aff071148 100644 (file)
@@ -93,7 +93,7 @@ typedef enum {
  */
 static inline struct bhv_vnode *vn_from_inode(struct inode *inode)
 {
-       return (bhv_vnode_t *)list_entry(inode, bhv_vnode_t, v_inode);
+       return container_of(inode, bhv_vnode_t, v_inode);
 }
 static inline struct inode *vn_to_inode(struct bhv_vnode *vnode)
 {
index 1d8ff103201c3bf78646ed2e9baeddac3c1b3019..6e6e56fb352d2fc56585f923f693c9231795c912 100644 (file)
  *
  */
 
-struct bhv_head_lock;
-
 /*
  * Behavior head.  Head of the chain of behaviors.
  * Contained within each virtualized object data structure.
  */
 typedef struct bhv_head {
        struct bhv_desc *bh_first;      /* first behavior in chain */
-       struct bhv_head_lock *bh_lockp; /* pointer to lock info struct */
 } bhv_head_t;
 
 /*
index 5fa0adb7e1737ad0ca4451409f412d73e1b5ce2f..86c1bf0bba9ea19bc0f38cdb98adfd76769ef053 100644 (file)
@@ -1961,9 +1961,9 @@ xfs_iunlink_remove(
        xfs_agino_t     agino;
        xfs_agino_t     next_agino;
        xfs_buf_t       *last_ibp;
-       xfs_dinode_t    *last_dip;
+       xfs_dinode_t    *last_dip = NULL;
        short           bucket_index;
-       int             offset, last_offset;
+       int             offset, last_offset = 0;
        int             error;
        int             agi_ok;
 
index d8f5d4cbe8b7b7819bb403e225389c54c22fd8b5..e730328636c31283c46cd2ce1fac1ccd18c4bf72 100644 (file)
@@ -1740,10 +1740,10 @@ xlog_write(xfs_mount_t *        mp,
           xlog_in_core_t       **commit_iclog,
           uint                 flags)
 {
-    xlog_t          *log    = mp->m_log;
+    xlog_t          *log = mp->m_log;
     xlog_ticket_t    *ticket = (xlog_ticket_t *)tic;
+    xlog_in_core_t   *iclog = NULL;  /* ptr to current in-core log */
     xlog_op_header_t *logop_head;    /* ptr to log operation header */
-    xlog_in_core_t   *iclog;        /* ptr to current in-core log */
     __psint_t       ptr;            /* copy address into data region */
     int                     len;            /* # xlog_write() bytes 2 still copy */
     int                     index;          /* region index currently copying */
index 55b4237c2153975e00ded0b662dcf36edd861ca2..3cb678e3a132997804998f7dbfea787b4a75a15a 100644 (file)
@@ -990,6 +990,8 @@ xlog_find_zeroed(
        xfs_daddr_t     num_scan_bblks;
        int             error, log_bbnum = log->l_logBBsize;
 
+       *blk_no = 0;
+
        /* check totally zeroed log */
        bp = xlog_get_bp(log, 1);
        if (!bp)
index 10dbf203c62f6f929ee709d6624121f744de231a..4be5c0b2d296b20a1feda5c4f1b47c38685f757b 100644 (file)
@@ -1721,15 +1721,14 @@ xfs_mount_log_sbunit(
  * is present to prevent thrashing).
  */
 
+#ifdef CONFIG_HOTPLUG_CPU
 /*
  * hot-plug CPU notifier support.
  *
- * We cannot use the hotcpu_register() function because it does
- * not allow notifier instances. We need a notifier per filesystem
- * as we need to be able to identify the filesystem to balance
- * the counters out. This is achieved by having a notifier block
- * embedded in the xfs_mount_t and doing pointer magic to get the
- * mount pointer from the notifier block address.
+ * We need a notifier per filesystem as we need to be able to identify
+ * the filesystem to balance the counters out. This is achieved by
+ * having a notifier block embedded in the xfs_mount_t and doing pointer
+ * magic to get the mount pointer from the notifier block address.
  */
 STATIC int
 xfs_icsb_cpu_notify(
@@ -1779,6 +1778,7 @@ xfs_icsb_cpu_notify(
 
        return NOTIFY_OK;
 }
+#endif /* CONFIG_HOTPLUG_CPU */
 
 int
 xfs_icsb_init_counters(
@@ -1791,9 +1791,11 @@ xfs_icsb_init_counters(
        if (mp->m_sb_cnts == NULL)
                return -ENOMEM;
 
+#ifdef CONFIG_HOTPLUG_CPU
        mp->m_icsb_notifier.notifier_call = xfs_icsb_cpu_notify;
        mp->m_icsb_notifier.priority = 0;
-       register_cpu_notifier(&mp->m_icsb_notifier);
+       register_hotcpu_notifier(&mp->m_icsb_notifier);
+#endif /* CONFIG_HOTPLUG_CPU */
 
        for_each_online_cpu(i) {
                cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
@@ -1812,7 +1814,7 @@ xfs_icsb_destroy_counters(
        xfs_mount_t     *mp)
 {
        if (mp->m_sb_cnts) {
-               unregister_cpu_notifier(&mp->m_icsb_notifier);
+               unregister_hotcpu_notifier(&mp->m_icsb_notifier);
                free_percpu(mp->m_sb_cnts);
        }
 }
@@ -2026,7 +2028,7 @@ xfs_icsb_balance_counter(
        xfs_sb_field_t  field,
        int             flags)
 {
-       uint64_t        count, resid = 0;
+       uint64_t        count, resid;
        int             weight = num_online_cpus();
        int             s;
 
@@ -2058,6 +2060,7 @@ xfs_icsb_balance_counter(
                break;
        default:
                BUG();
+               count = resid = 0;      /* quiet, gcc */
                break;
        }
 
index 0c1e42b037efe63058819f275e20b0fd7cf9186b..5a0b678956e0e3ca616efb76ffb9d827f6d159fa 100644 (file)
@@ -1929,7 +1929,7 @@ xfs_growfs_rt(
        /*
         * Initial error checking.
         */
-       if (mp->m_rtdev_targp || mp->m_rbmip == NULL ||
+       if (mp->m_rtdev_targp == NULL || mp->m_rbmip == NULL ||
            (nrblocks = in->newblocks) <= sbp->sb_rblocks ||
            (sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize)))
                return XFS_ERROR(EINVAL);
index cb65c3a603f56a776cfef5a7a0def8c6f2d77108..9dc88b380608e6f29a6bef4c7ee5c21945367f0f 100644 (file)
@@ -338,8 +338,6 @@ typedef void (*xfs_trans_callback_t)(struct xfs_trans *, void *);
 typedef struct xfs_trans {
        unsigned int            t_magic;        /* magic number */
        xfs_log_callback_t      t_logcb;        /* log callback struct */
-       struct xfs_trans        *t_forw;        /* async list pointers */
-       struct xfs_trans        *t_back;        /* async list pointers */
        unsigned int            t_type;         /* transaction type */
        unsigned int            t_log_res;      /* amt of log space resvd */
        unsigned int            t_log_count;    /* count for perm log res */
@@ -364,9 +362,11 @@ typedef struct xfs_trans {
        long                    t_res_fdblocks_delta; /* on-disk only chg */
        long                    t_frextents_delta;/* superblock freextents chg*/
        long                    t_res_frextents_delta; /* on-disk only chg */
+#ifdef DEBUG
        long                    t_ag_freeblks_delta; /* debugging counter */
        long                    t_ag_flist_delta; /* debugging counter */
        long                    t_ag_btree_delta; /* debugging counter */
+#endif
        long                    t_dblocks_delta;/* superblock dblocks change */
        long                    t_agcount_delta;/* superblock agcount change */
        long                    t_imaxpct_delta;/* superblock imaxpct change */
index 00a6b7dc24a0a6ed047999b85f4eeca4f1494d1f..23cfa58377283b073f09503734581ea4df80edf0 100644 (file)
@@ -2603,8 +2603,7 @@ xfs_link(
        vn_trace_entry(src_vp, __FUNCTION__, (inst_t *)__return_address);
 
        target_namelen = VNAMELEN(dentry);
-       if (VN_ISDIR(src_vp))
-               return XFS_ERROR(EPERM);
+       ASSERT(!VN_ISDIR(src_vp));
 
        sip = xfs_vtoi(src_vp);
        tdp = XFS_BHVTOI(target_dir_bdp);
@@ -2699,9 +2698,8 @@ xfs_link(
        xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
 
        error = xfs_bumplink(tp, sip);
-       if (error) {
+       if (error)
                goto abort_return;
-       }
 
        /*
         * If this is a synchronous mount, make sure that the
@@ -2719,9 +2717,8 @@ xfs_link(
        }
 
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
-       if (error) {
+       if (error)
                goto std_return;
-       }
 
        /* Fall through to std_return with error = 0. */
 std_return:
@@ -2742,6 +2739,8 @@ std_return:
        xfs_trans_cancel(tp, cancel_flags);
        goto std_return;
 }
+
+
 /*
  * xfs_mkdir
  *
index dba70c62a16c0d3a56df6ffebd917983d0367f3b..457c34b6eb09337bc87421aeb0edfe0b35edd2e7 100644 (file)
@@ -435,7 +435,7 @@ static inline void t2_outl(u32 b, unsigned long addr)
        set_hae(msb); \
 }
 
-static spinlock_t t2_hae_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(t2_hae_lock);
 
 __EXTERN_INLINE u8 t2_readb(const volatile void __iomem *xaddr)
 {
index ca9d43b6350276b1bf07e675907033b52690a9e8..a37db0f95092f495a02819a7382631c34b686c37 100644 (file)
@@ -2,8 +2,6 @@
 #define _ALPHA_HW_IRQ_H
 
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
-
 extern volatile unsigned long irq_err_count;
 
 #ifdef CONFIG_ALPHA_GENERIC
index 3c327c4043734078a6f726c71fab015a82787a2a..f985069e6d011dd41784e83e65f6e6729fe49fff 100644 (file)
@@ -33,9 +33,7 @@
  * bus_to_virt: Used to convert an address for DMA operations
  *              to an address that the kernel can use.
  */
-#define __virt_to_bus__is_a_macro
 #define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x) __phys_to_virt(x)
 
 #endif
index 4a1bfd78a0fe11cbcb56d5c65e261bab7c265b13..53e923dba76e658b4d4613e8099ae424c2ce2854 100644 (file)
@@ -23,9 +23,7 @@
  * There is something to do here later !, Mar 2000, Jungjun Kim
  */
 
-#define __virt_to_bus__is_a_macro
 #define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x)       __phys_to_virt(x)
 
 #endif
index d09ae32cd2f4c011e03e34761294f45c9b888040..5ad90127915f63cfc69f2629ebb0772ff4280f55 100644 (file)
@@ -30,9 +30,7 @@
  * bus_to_virt: Used to convert an address for DMA operations
  *              to an address that the kernel can use.
  */
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)       (x - PAGE_OFFSET +  PHYS_OFFSET)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)       (x -  PHYS_OFFSET + PAGE_OFFSET)
+#define __virt_to_bus(x)       (x - PAGE_OFFSET + PHYS_OFFSET)
+#define __bus_to_virt(x)       (x - PHYS_OFFSET + PAGE_OFFSET)
 
 #endif
index d0a72201ee96a344163a849a9998f41f8274c9e9..3927b1d61b17dd593ebfd45a6814469c2e820377 100644 (file)
 #define IXP23XX_PCI_CPP_ADDR_BITS      IXP23XX_PCI_CSR(0x0160)
 
 
-#ifndef __ASSEMBLY__
-/*
- * Is system memory on the XSI or CPP bus?
- */
-static inline unsigned ixp23xx_cpp_boot(void)
-{
-       return (*IXP23XX_EXP_CFG0 & IXP23XX_EXP_CFG0_XSI_NOT_PRES);
-}
-#endif
-
-
 #endif
index 19a73b39c8640491dc034bdbf5629edad8cd69c1..56e16d66645a090fe1913ffeaafeb8e2a7d8dfa2 100644 (file)
@@ -43,5 +43,15 @@ extern struct sys_timer ixp23xx_timer;
 
 #define IXP23XX_UART_XTAL              14745600
 
+#ifndef __ASSEMBLY__
+/*
+ * Is system memory on the XSI or CPP bus?
+ */
+static inline unsigned ixp23xx_cpp_boot(void)
+{
+       return (*IXP23XX_EXP_CFG0 & IXP23XX_EXP_CFG0_XSI_NOT_PRES);
+}
+#endif
+
 
 #endif
index 013575e6a9a1bd5b3d262cc81fc825c173aa3a60..16c1110f2304c1a08d72adcca3cedc90e054f1c5 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef __ASM_ARCH_UNCOMPRESS_H
 #define __ASM_ARCH_UNCOMPRESS_H
 
-#include <asm/hardware.h>
+#include <asm/arch/ixp23xx.h>
 #include <linux/serial_reg.h>
 
 #define UART_BASE      ((volatile u32 *)IXP23XX_UART1_PHYS)
index 84aca61cbaa3d70c2edc629dc257be5593c753b9..a0a1248751646053c9f969cf1f0d181b1911de68 100644 (file)
@@ -7,25 +7,23 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * S3C2440 Signal Drive Strength Control
- *
- *  Changelog:
- *    11-Aug-2004     BJD     Created file
- *    25-Aug-2004     BJD     Added the _SELECT_* defs for using with functions
+ * S3C2440/S3C2412 Signal Drive Strength Control
 */
 
 
 #ifndef __ASM_ARCH_REGS_DSC_H
 #define __ASM_ARCH_REGS_DSC_H "2440-dsc"
 
-#ifdef CONFIG_CPU_S3C2440
+#if defined(CONFIG_CPU_S3C2412)
+#define S3C2412_DSC0      S3C2410_GPIOREG(0xdc)
+#define S3C2412_DSC1      S3C2410_GPIOREG(0xe0)
+#endif
+
+#if defined(CONFIG_CPU_S3C2440)
 
 #define S3C2440_DSC0      S3C2410_GPIOREG(0xc4)
 #define S3C2440_DSC1      S3C2410_GPIOREG(0xc8)
 
-#define S3C2412_DSC0      S3C2410_GPIOREG(0xdc)
-#define S3C2412_DSC1      S3C2410_GPIOREG(0xe0)
-
 #define S3C2440_SELECT_DSC0 (0)
 #define S3C2440_SELECT_DSC1 (1<<31)
 
index 7cff235e667aeea2ef79c9d002bebc85b2d95abb..c1470c695c33556ea6a85f9d4efc4287fc08dea8 100644 (file)
 #define S3C2440_NFESTAT1 S3C2410_NFREG(0x28)
 #define S3C2440_NFMECC0  S3C2410_NFREG(0x2C)
 #define S3C2440_NFMECC1  S3C2410_NFREG(0x30)
-#define S3C2440_NFSECC   S3C2410_NFREG(0x34)
+#define S3C2440_NFSECC   S3C24E10_NFREG(0x34)
 #define S3C2440_NFSBLK   S3C2410_NFREG(0x38)
 #define S3C2440_NFEBLK   S3C2410_NFREG(0x3C)
 
+#define S3C2412_NFSBLK         S3C2410_NFREG(0x20)
+#define S3C2412_NFEBLK         S3C2410_NFREG(0x24)
+#define S3C2412_NFSTAT         S3C2410_NFREG(0x28)
+#define S3C2412_NFMECC_ERR0    S3C2410_NFREG(0x2C)
+#define S3C2412_NFMECC_ERR1    S3C2410_NFREG(0x30)
+#define S3C2412_NFMECC0                S3C2410_NFREG(0x34)
+#define S3C2412_NFMECC1                S3C2410_NFREG(0x38)
+#define S3C2412_NFSECC         S3C2410_NFREG(0x3C)
+
 #define S3C2410_NFCONF_EN          (1<<15)
 #define S3C2410_NFCONF_512BYTE     (1<<14)
 #define S3C2410_NFCONF_4STEP       (1<<13)
 #define S3C2440_NFSTAT_RnB_CHANGE      (1<<2)
 #define S3C2440_NFSTAT_ILLEGAL_ACCESS  (1<<3)
 
+#define S3C2412_NFCONF_NANDBOOT                (1<<31)
+#define S3C2412_NFCONF_ECCCLKCON       (1<<30)
+#define S3C2412_NFCONF_ECC_MLC         (1<<24)
+#define S3C2412_NFCONF_TACLS_MASK      (7<<12) /* 1 extra bit of Tacls */
+
+#define S3C2412_NFCONT_ECC4_DIRWR      (1<<18)
+#define S3C2412_NFCONT_LOCKTIGHT       (1<<17)
+#define S3C2412_NFCONT_SOFTLOCK                (1<<16)
+#define S3C2412_NFCONT_ECC4_ENCINT     (1<<13)
+#define S3C2412_NFCONT_ECC4_DECINT     (1<<12)
+#define S3C2412_NFCONT_MAIN_ECC_LOCK   (1<<7)
+#define S3C2412_NFCONT_INIT_MAIN_ECC   (1<<5)
+#define S3C2412_NFCONT_nFCE1           (1<<2)
+#define S3C2412_NFCONT_nFCE0           (1<<1)
+
+#define S3C2412_NFSTAT_ECC_ENCDONE     (1<<7)
+#define S3C2412_NFSTAT_ECC_DECDONE     (1<<6)
+#define S3C2412_NFSTAT_ILLEGAL_ACCESS  (1<<5)
+#define S3C2412_NFSTAT_RnB_CHANGE      (1<<4)
+#define S3C2412_NFSTAT_nFCE1           (1<<3)
+#define S3C2412_NFSTAT_nFCE0           (1<<2)
+#define S3C2412_NFSTAT_Res1            (1<<1)
+#define S3C2412_NFSTAT_READY           (1<<0)
+
+#define S3C2412_NFECCERR_SERRDATA(x)   (((x) >> 21) & 0xf)
+#define S3C2412_NFECCERR_SERRBIT(x)    (((x) >> 18) & 0x7)
+#define S3C2412_NFECCERR_MERRDATA(x)   (((x) >> 7) & 0x3ff)
+#define S3C2412_NFECCERR_MERRBIT(x)    (((x) >> 4) & 0x7)
+#define S3C2412_NFECCERR_SPARE_ERR(x)  (((x) >> 2) & 0x3)
+#define S3C2412_NFECCERR_MAIN_ERR(x)   (((x) >> 2) & 0x3)
+#define S3C2412_NFECCERR_NONE          (0)
+#define S3C2412_NFECCERR_1BIT          (1)
+#define S3C2412_NFECCERR_MULTIBIT      (2)
+#define S3C2412_NFECCERR_ECCAREA       (3)
+
+
+
 #endif /* __ASM_ARM_REGS_NAND */
 
index 4c80ec519d45d8760fc18f73ece1e439adf012de..ca54eb0f12d75cc15ea35281d5cb72f3050171cb 100644 (file)
 #ifndef __ASM_BUGS_H
 #define __ASM_BUGS_H
 
+#ifdef CONFIG_MMU
 extern void check_writebuffer_bugs(void);
 
 #define check_bugs() check_writebuffer_bugs()
+#else
+#define check_bugs() do { } while (0)
+#endif
 
 #endif
index f8ea2de4848ea7ae075836718342952a86cda1d0..4c2885abbe6c950f04d06c6345bb6358f591421b 100644 (file)
@@ -50,6 +50,8 @@
 #define domain_val(dom,type)   ((type) << (2*(dom)))
 
 #ifndef __ASSEMBLY__
+
+#ifdef CONFIG_MMU
 #define set_domain(x)                                  \
        do {                                            \
        __asm__ __volatile__(                           \
        set_domain(thread->cpu_domain);                         \
        } while (0)
 
+#else
+#define set_domain(x)          do { } while (0)
+#define modify_domain(dom,type)        do { } while (0)
+#endif
+
 #endif
 #endif /* !__ASSEMBLY__ */
index 132c3c5628b2a4b4d5be60bee7f1a41f04e627d0..6af4e6bd1290c261dcba28096949fe6262145c8a 100644 (file)
@@ -72,6 +72,14 @@ union fp_state {
 
 #define FP_SIZE (sizeof(union fp_state) / sizeof(int))
 
+struct crunch_state {
+       unsigned int    mvdx[16][2];
+       unsigned int    mvax[4][3];
+       unsigned int    dspsc[2];
+};
+
+#define CRUNCH_SIZE    sizeof(struct crunch_state)
+
 #endif
 
 #endif
index e8ea67c97c73d3526b3c7025dbc9a468e1ef6331..cef5364ed5feb0531cc39b3bee6ccdf01426562d 100644 (file)
@@ -16,8 +16,6 @@ struct map_desc {
        unsigned int type;
 };
 
-struct meminfo;
-
 #define MT_DEVICE              0
 #define MT_CACHECLEAN          1
 #define MT_MINICLEAN           2
@@ -28,7 +26,8 @@ struct meminfo;
 #define MT_IXP2000_DEVICE      7
 #define MT_NONSHARED_DEVICE    8
 
-extern void create_memmap_holes(struct meminfo *);
-extern void memtable_init(struct meminfo *);
+#ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
-extern void setup_io_desc(void);
+#else
+#define iotable_init(map,num)  do { } while (0)
+#endif
index 25d540ed0079bf2063921dddbe83b9fdadf67949..923e0ca66200c1f0a592ff470528d4c524a15583 100644 (file)
@@ -28,7 +28,7 @@ struct hw_pci {
 struct pci_sys_data {
        struct list_head node;
        int             busnr;          /* primary bus number                   */
-       unsigned long   mem_offset;     /* bus->cpu memory mapping offset       */
+       u64             mem_offset;     /* bus->cpu memory mapping offset       */
        unsigned long   io_offset;      /* bus->cpu IO mapping offset           */
        struct pci_bus  *bus;           /* PCI bus                              */
        struct resource *resource[3];   /* Primary PCI bus resources            */
index 731e321a57d1722779b93babdfae17742aca8440..94f973b704f1578f1f88e42dec61a8ac2670007d 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/include/asm-arm/memory.h
  *
  *  Copyright (C) 2000-2002 Russell King
+ *  modification for nommu, Hyok S. Choi, 2004
  *
  * 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
@@ -26,6 +27,8 @@
 #include <asm/arch/memory.h>
 #include <asm/sizes.h>
 
+#ifdef CONFIG_MMU
+
 #ifndef TASK_SIZE
 /*
  * TASK_SIZE - the maximum size of a user space task.
 #define PAGE_OFFSET            UL(0xc0000000)
 #endif
 
+/*
+ * The module space lives between the addresses given by TASK_SIZE
+ * and PAGE_OFFSET - it must be within 32MB of the kernel text.
+ */
+#define MODULE_END             (PAGE_OFFSET)
+#define MODULE_START           (MODULE_END - 16*1048576)
+
+#if TASK_SIZE > MODULE_START
+#error Top of user space clashes with start of module space
+#endif
+
+/*
+ * The XIP kernel gets mapped at the bottom of the module vm area.
+ * Since we use sections to map it, this macro replaces the physical address
+ * with its virtual address while keeping offset from the base section.
+ */
+#define XIP_VIRT_ADDR(physaddr)  (MODULE_START + ((physaddr) & 0x000fffff))
+
+#else /* CONFIG_MMU */
+
+/*
+ * The limitation of user task size can grow up to the end of free ram region.
+ * It is difficult to define and perhaps will never meet the original meaning
+ * of this define that was meant to.
+ * Fortunately, there is no reference for this in noMMU mode, for now.
+ */
+#ifndef TASK_SIZE
+#define TASK_SIZE              (CONFIG_DRAM_SIZE)
+#endif
+
+#ifndef TASK_UNMAPPED_BASE
+#define TASK_UNMAPPED_BASE     UL(0x00000000)
+#endif
+
+#ifndef PHYS_OFFSET
+#define PHYS_OFFSET            (CONFIG_DRAM_BASE)
+#endif
+
+#ifndef END_MEM
+#define END_MEM                (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE)
+#endif
+
+#ifndef PAGE_OFFSET
+#define PAGE_OFFSET            (PHYS_OFFSET)
+#endif
+
+/*
+ * The module can be at any place in ram in nommu mode.
+ */
+#define MODULE_END             (END_MEM)
+#define MODULE_START           (PHYS_OFFSET)
+
+#endif /* !CONFIG_MMU */
+
 /*
  * Size of DMA-consistent memory region.  Must be multiple of 2M,
  * between 2MB and 14MB inclusive.
 #define        __phys_to_pfn(paddr)    ((paddr) >> PAGE_SHIFT)
 #define        __pfn_to_phys(pfn)      ((pfn) << PAGE_SHIFT)
 
-/*
- * The module space lives between the addresses given by TASK_SIZE
- * and PAGE_OFFSET - it must be within 32MB of the kernel text.
- */
-#define MODULE_END     (PAGE_OFFSET)
-#define MODULE_START   (MODULE_END - 16*1048576)
-
-#if TASK_SIZE > MODULE_START
-#error Top of user space clashes with start of module space
-#endif
-
-/*
- * The XIP kernel gets mapped at the bottom of the module vm area.
- * Since we use sections to map it, this macro replaces the physical address
- * with its virtual address while keeping offset from the base section.
- */
-#define XIP_VIRT_ADDR(physaddr)  (MODULE_START + ((physaddr) & 0x000fffff))
-
 #ifndef __ASSEMBLY__
 
 /*
index a457cb71984f58cdd8ba6de24a8f33a93b9bdd95..23dde52e0945f31c24ddd9fc4ddc1b8e66a74163 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ARM_MMU_H
 #define __ARM_MMU_H
 
+#ifdef CONFIG_MMU
+
 typedef struct {
 #if __LINUX_ARM_ARCH__ >= 6
        unsigned int id;
@@ -13,4 +15,18 @@ typedef struct {
 #define ASID(mm)       (0)
 #endif
 
+#else
+
+/*
+ * From nommu.h:
+ *  Copyright (C) 2002, David McCullough <davidm@snapgear.com>
+ *  modified for 2.6 by Hyok S. Choi <hyok.choi@samsung.com>
+ */
+typedef struct {
+       struct vm_list_struct   *vmlist;
+       unsigned long           end_brk;
+} mm_context_t;
+
+#endif
+
 #endif
index 81c59facea3bead1184df5cf0359058eb9a2d366..9fadb01e030d15a4fd67dda4ac143ff52406be46 100644 (file)
@@ -82,6 +82,7 @@ static inline void
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
          struct task_struct *tsk)
 {
+#ifdef CONFIG_MMU
        unsigned int cpu = smp_processor_id();
 
        if (prev != next) {
@@ -91,6 +92,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
                if (cache_is_vivt())
                        cpu_clear(cpu, prev->cpu_vm_mask);
        }
+#endif
 }
 
 #define deactivate_mm(tsk,mm)  do { } while (0)
diff --git a/include/asm-arm/page-nommu.h b/include/asm-arm/page-nommu.h
new file mode 100644 (file)
index 0000000..a1bcad0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  linux/include/asm-arm/page-nommu.h
+ *
+ *  Copyright (C) 2004 Hyok S. Choi
+ *
+ * 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_PAGE_NOMMU_H
+#define _ASMARM_PAGE_NOMMU_H
+
+#if !defined(CONFIG_SMALL_TASKS) && PAGE_SHIFT < 13
+#define KTHREAD_SIZE (8192)
+#else
+#define KTHREAD_SIZE PAGE_SIZE
+#endif
+#define get_user_page(vaddr)           __get_free_page(GFP_KERNEL)
+#define free_user_page(page, addr)     free_page(addr)
+
+#define clear_page(page)       memset((page), 0, PAGE_SIZE)
+#define copy_page(to,from)     memcpy((to), (from), PAGE_SIZE)
+
+#define clear_user_page(page, vaddr, pg)       clear_page(page)
+#define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef unsigned long pte_t;
+typedef unsigned long pmd_t;
+typedef unsigned long pgd_t[2];
+typedef unsigned long pgprot_t;
+
+#define pte_val(x)      (x)
+#define pmd_val(x)      (x)
+#define pgd_val(x)     ((x)[0])
+#define pgprot_val(x)   (x)
+
+#define __pte(x)        (x)
+#define __pmd(x)        (x)
+#define __pgprot(x)     (x)
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+
+#endif
index 66cfeb5290ea5c0e077f67db6bd154c5768ab9b1..63d12f0244c50d09ab60c89d56159196440fb024 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#ifndef CONFIG_MMU
+
+#include "page-nommu.h"
+
+#else
+
 #include <asm/glue.h>
 
 /*
@@ -171,6 +177,8 @@ typedef unsigned long pgprot_t;
 /* the upper-most page table pointer */
 extern pmd_t *top_pmd;
 
+#endif /* CONFIG_MMU */
+
 #include <asm/memory.h>
 
 #endif /* !__ASSEMBLY__ */
index c4ac2e67768dcdbf6077e3fc385e2a192ab569d1..4d43945529118a8ea7e92241771a6f3253a1e93a 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
+#define check_pgt_cache()              do { } while (0)
+
+#ifdef CONFIG_MMU
+
 #define _PAGE_USER_TABLE       (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
 #define _PAGE_KERNEL_TABLE     (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
 
@@ -32,8 +36,6 @@ extern void free_pgd_slow(pgd_t *pgd);
 #define pgd_alloc(mm)                  get_pgd_slow(mm)
 #define pgd_free(pgd)                  free_pgd_slow(pgd)
 
-#define check_pgt_cache()              do { } while (0)
-
 /*
  * Allocate one PTE table.
  *
@@ -126,4 +128,6 @@ pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *ptep)
        __pmd_populate(pmdp, page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE);
 }
 
+#endif /* CONFIG_MMU */
+
 #endif
diff --git a/include/asm-arm/pgtable-nommu.h b/include/asm-arm/pgtable-nommu.h
new file mode 100644 (file)
index 0000000..b13322d
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *  linux/include/asm-arm/pgtable-nommu.h
+ *
+ *  Copyright (C) 1995-2002 Russell King
+ *  Copyright (C) 2004  Hyok S. Choi
+ *
+ * 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_PGTABLE_NOMMU_H
+#define _ASMARM_PGTABLE_NOMMU_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/io.h>
+
+/*
+ * Trivial page table functions.
+ */
+#define pgd_present(pgd)       (1)
+#define pgd_none(pgd)          (0)
+#define pgd_bad(pgd)           (0)
+#define pgd_clear(pgdp)
+#define kern_addr_valid(addr)  (1)
+#define        pmd_offset(a, b)        ((void *)0)
+/* FIXME */
+/*
+ * PMD_SHIFT determines the size of the area a second-level page table can map
+ * PGDIR_SHIFT determines what a third-level page table entry can map
+ */
+#define PGDIR_SHIFT            21
+
+#define PGDIR_SIZE             (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK             (~(PGDIR_SIZE-1))
+/* FIXME */
+
+#define PAGE_NONE      __pgprot(0)
+#define PAGE_SHARED    __pgprot(0)
+#define PAGE_COPY      __pgprot(0)
+#define PAGE_READONLY  __pgprot(0)
+#define PAGE_KERNEL    __pgprot(0)
+
+//extern void paging_init(struct meminfo *, struct machine_desc *);
+#define swapper_pg_dir ((pgd_t *) 0)
+
+#define __swp_type(x)          (0)
+#define __swp_offset(x)                (0)
+#define __swp_entry(typ,off)   ((swp_entry_t) { ((typ) | ((off) << 7)) })
+#define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x)  ((pte_t) { (x).val })
+
+
+typedef pte_t *pte_addr_t;
+
+static inline int pte_file(pte_t pte) { return 0; }
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+#define ZERO_PAGE(vaddr)       (virt_to_page(0))
+
+/*
+ * Mark the prot value as uncacheable and unbufferable.
+ */
+#define pgprot_noncached(prot) __pgprot(0)
+#define pgprot_writecombine(prot) __pgprot(0)
+
+
+/*
+ * These would be in other places but having them here reduces the diffs.
+ */
+extern unsigned int kobjsize(const void *objp);
+extern int is_in_rom(unsigned long);
+
+/*
+ * No page table caches to initialise.
+ */
+#define pgtable_cache_init()   do { } while (0)
+#define io_remap_page_range    remap_page_range
+#define io_remap_pfn_range     remap_pfn_range
+
+#define MK_IOSPACE_PFN(space, pfn)     (pfn)
+#define GET_IOSPACE(pfn)               0
+#define GET_PFN(pfn)                   (pfn)
+
+
+/*
+ * All 32bit addresses are effectively valid for vmalloc...
+ * Sort of meaningless for non-VM targets.
+ */
+#define        VMALLOC_START   0
+#define        VMALLOC_END     0xffffffff
+
+#define FIRST_USER_ADDRESS      (0)
+
+#else 
+
+/*
+ * dummy tlb and user structures.
+ */
+#define v3_tlb_fns     (0)
+#define v4_tlb_fns     (0)
+#define v4wb_tlb_fns   (0)
+#define v4wbi_tlb_fns  (0)
+#define v6_tlb_fns     (0)
+
+#define v3_user_fns    (0)
+#define v4_user_fns    (0)
+#define v4_mc_user_fns (0)
+#define v4wb_user_fns  (0)
+#define v4wt_user_fns  (0)
+#define v6_user_fns    (0)
+#define xscale_mc_user_fns (0)
+
+#endif /*__ASSEMBLY__*/
+
+#endif /* _ASMARM_PGTABLE_H */
index e85c08d78ddadf5e85f14818fc858c94692e40d2..8d3919c6458c6c9326ef35a35ee7c848d34ac467 100644 (file)
 #define _ASMARM_PGTABLE_H
 
 #include <asm-generic/4level-fixup.h>
+#include <asm/proc-fns.h>
+
+#ifndef CONFIG_MMU
+
+#include "pgtable-nommu.h"
+
+#else
 
 #include <asm/memory.h>
-#include <asm/proc-fns.h>
 #include <asm/arch/vmalloc.h>
 
 /*
@@ -378,4 +384,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
 #endif /* !__ASSEMBLY__ */
 
+#endif /* CONFIG_MMU */
+
 #endif /* _ASMARM_PGTABLE_H */
index e9310895e79dae741c6104ba85f63a5afc660cb2..1bde92cdaebd01739c3db199a438f47a7ffd0493 100644 (file)
 
 #include <asm/memory.h>
 
+#ifdef CONFIG_MMU
+
 #define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
 
 #define cpu_get_pgd()  \
                (pgd_t *)phys_to_virt(pg);              \
        })
 
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* __ASM_PROCFNS_H */
index 2bebe3dc0a30c5a8be30081d11f2e14fa798f4da..5a8ef787dbf81c0c3ec5caf79471fe69a3033f07 100644 (file)
 
 #define PTRACE_SET_SYSCALL     23
 
+/* PTRACE_SYSCALL is 24 */
+
+#define PTRACE_GETCRUNCHREGS   25
+#define PTRACE_SETCRUNCHREGS   26
+
 /*
  * PSR bits
  */
index cfbccb63c67b4df54523fa3942b2ba6b096bd09b..c46b5c84275f3f2f5b2ac91d8a60002963fdc9f5 100644 (file)
@@ -59,6 +59,7 @@ struct thread_info {
        struct cpu_context_save cpu_context;    /* cpu context */
        __u8                    used_cp[16];    /* thread used copro */
        unsigned long           tp_value;
+       struct crunch_state     crunchstate;
        union fp_state          fpstate __attribute__((aligned(8)));
        union vfp_state         vfpstate;
        struct restart_block    restart_block;
@@ -101,6 +102,11 @@ extern void free_thread_info(struct thread_info *);
 #define thread_saved_fp(tsk)   \
        ((unsigned long)(task_thread_info(tsk)->cpu_context.fp))
 
+extern void crunch_task_disable(struct thread_info *);
+extern void crunch_task_copy(struct thread_info *, void *);
+extern void crunch_task_restore(struct thread_info *, void *);
+extern void crunch_task_release(struct thread_info *);
+
 extern void iwmmxt_task_disable(struct thread_info *);
 extern void iwmmxt_task_copy(struct thread_info *, void *);
 extern void iwmmxt_task_restore(struct thread_info *, void *);
index 064f0f5e8e2b9e3361082dbc420b2e6248263c40..87aba57a66c40d5b0f10fe199c3159fa5710a9e3 100644 (file)
@@ -40,16 +40,25 @@ struct exception_table_entry
 
 extern int fixup_exception(struct pt_regs *regs);
 
+/*
+ * These two are intentionally not defined anywhere - if the kernel
+ * code generates any references to them, that's a bug.
+ */
+extern int __get_user_bad(void);
+extern int __put_user_bad(void);
+
 /*
  * Note that this is actually 0x1,0000,0000
  */
 #define KERNEL_DS      0x00000000
-#define USER_DS                TASK_SIZE
-
 #define get_ds()       (KERNEL_DS)
+
+#ifdef CONFIG_MMU
+
+#define USER_DS                TASK_SIZE
 #define get_fs()       (current_thread_info()->addr_limit)
 
-static inline void set_fs (mm_segment_t fs)
+static inline void set_fs(mm_segment_t fs)
 {
        current_thread_info()->addr_limit = fs;
        modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);
@@ -75,8 +84,6 @@ static inline void set_fs (mm_segment_t fs)
                : "cc"); \
        flag; })
 
-#define access_ok(type,addr,size)      (__range_ok(addr,size) == 0)
-
 /*
  * Single-value transfer routines.  They automatically use the right
  * size if we just have the right pointer type.  Note that the functions
@@ -87,20 +94,10 @@ static inline void set_fs (mm_segment_t fs)
  * fixup code, but there are a few places where it intrudes on the
  * main code path.  When we only write to user space, there is no
  * problem.
- *
- * The "__xxx" versions of the user access functions do not verify the
- * address space - it must have been done previously with a separate
- * "access_ok()" call.
- *
- * The "xxx_error" versions set the third argument to EFAULT if an
- * error occurs, and leave it unchanged on success.  Note that these
- * versions are void (ie, don't return a value as such).
  */
-
 extern int __get_user_1(void *);
 extern int __get_user_2(void *);
 extern int __get_user_4(void *);
-extern int __get_user_bad(void);
 
 #define __get_user_x(__r2,__p,__e,__s,__i...)                          \
           __asm__ __volatile__ (                                       \
@@ -131,6 +128,74 @@ extern int __get_user_bad(void);
                __e;                                                    \
        })
 
+extern int __put_user_1(void *, unsigned int);
+extern int __put_user_2(void *, unsigned int);
+extern int __put_user_4(void *, unsigned int);
+extern int __put_user_8(void *, unsigned long long);
+
+#define __put_user_x(__r2,__p,__e,__s)                                 \
+          __asm__ __volatile__ (                                       \
+               __asmeq("%0", "r0") __asmeq("%2", "r2")                 \
+               "bl     __put_user_" #__s                               \
+               : "=&r" (__e)                                           \
+               : "0" (__p), "r" (__r2)                                 \
+               : "ip", "lr", "cc")
+
+#define put_user(x,p)                                                  \
+       ({                                                              \
+               const register typeof(*(p)) __r2 asm("r2") = (x);       \
+               const register typeof(*(p)) __user *__p asm("r0") = (p);\
+               register int __e asm("r0");                             \
+               switch (sizeof(*(__p))) {                               \
+               case 1:                                                 \
+                       __put_user_x(__r2, __p, __e, 1);                \
+                       break;                                          \
+               case 2:                                                 \
+                       __put_user_x(__r2, __p, __e, 2);                \
+                       break;                                          \
+               case 4:                                                 \
+                       __put_user_x(__r2, __p, __e, 4);                \
+                       break;                                          \
+               case 8:                                                 \
+                       __put_user_x(__r2, __p, __e, 8);                \
+                       break;                                          \
+               default: __e = __put_user_bad(); break;                 \
+               }                                                       \
+               __e;                                                    \
+       })
+
+#else /* CONFIG_MMU */
+
+/*
+ * uClinux has only one addr space, so has simplified address limits.
+ */
+#define USER_DS                        KERNEL_DS
+
+#define segment_eq(a,b)                (1)
+#define __addr_ok(addr)                (1)
+#define __range_ok(addr,size)  (0)
+#define get_fs()               (KERNEL_DS)
+
+static inline void set_fs(mm_segment_t fs)
+{
+}
+
+#define get_user(x,p)  __get_user(x,p)
+#define put_user(x,p)  __put_user(x,p)
+
+#endif /* CONFIG_MMU */
+
+#define access_ok(type,addr,size)      (__range_ok(addr,size) == 0)
+
+/*
+ * The "__xxx" versions of the user access functions do not verify the
+ * address space - it must have been done previously with a separate
+ * "access_ok()" call.
+ *
+ * The "xxx_error" versions set the third argument to EFAULT if an
+ * error occurs, and leave it unchanged on success.  Note that these
+ * versions are void (ie, don't return a value as such).
+ */
 #define __get_user(x,ptr)                                              \
 ({                                                                     \
        long __gu_err = 0;                                              \
@@ -212,43 +277,6 @@ do {                                                                       \
        : "r" (addr), "i" (-EFAULT)                             \
        : "cc")
 
-extern int __put_user_1(void *, unsigned int);
-extern int __put_user_2(void *, unsigned int);
-extern int __put_user_4(void *, unsigned int);
-extern int __put_user_8(void *, unsigned long long);
-extern int __put_user_bad(void);
-
-#define __put_user_x(__r2,__p,__e,__s)                                 \
-          __asm__ __volatile__ (                                       \
-               __asmeq("%0", "r0") __asmeq("%2", "r2")                 \
-               "bl     __put_user_" #__s                               \
-               : "=&r" (__e)                                           \
-               : "0" (__p), "r" (__r2)                                 \
-               : "ip", "lr", "cc")
-
-#define put_user(x,p)                                                  \
-       ({                                                              \
-               const register typeof(*(p)) __r2 asm("r2") = (x);       \
-               const register typeof(*(p)) __user *__p asm("r0") = (p);\
-               register int __e asm("r0");                             \
-               switch (sizeof(*(__p))) {                               \
-               case 1:                                                 \
-                       __put_user_x(__r2, __p, __e, 1);                \
-                       break;                                          \
-               case 2:                                                 \
-                       __put_user_x(__r2, __p, __e, 2);                \
-                       break;                                          \
-               case 4:                                                 \
-                       __put_user_x(__r2, __p, __e, 4);                \
-                       break;                                          \
-               case 8:                                                 \
-                       __put_user_x(__r2, __p, __e, 8);                \
-                       break;                                          \
-               default: __e = __put_user_bad(); break;                 \
-               }                                                       \
-               __e;                                                    \
-       })
-
 #define __put_user(x,ptr)                                              \
 ({                                                                     \
        long __pu_err = 0;                                              \
@@ -353,66 +381,54 @@ do {                                                                      \
        : "r" (x), "i" (-EFAULT)                                \
        : "cc")
 
-extern unsigned long __arch_copy_from_user(void *to, const void __user *from, unsigned long n);
-extern unsigned long __arch_copy_to_user(void __user *to, const void *from, unsigned long n);
-extern unsigned long __arch_clear_user(void __user *addr, unsigned long n);
-extern unsigned long __arch_strncpy_from_user(char *to, const char __user *from, unsigned long count);
-extern unsigned long __arch_strnlen_user(const char __user *s, long n);
+
+#ifdef CONFIG_MMU
+extern unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n);
+extern unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n);
+extern unsigned long __clear_user(void __user *addr, unsigned long n);
+#else
+#define __copy_from_user(to,from,n)    (memcpy(to, (void __force *)from, n), 0)
+#define __copy_to_user(to,from,n)      (memcpy((void __force *)to, from, n), 0)
+#define __clear_user(addr,n)           (memset((void __force *)addr, 0, n), 0)
+#endif
+
+extern unsigned long __strncpy_from_user(char *to, const char __user *from, unsigned long count);
+extern unsigned long __strnlen_user(const char __user *s, long n);
 
 static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        if (access_ok(VERIFY_READ, from, n))
-               n = __arch_copy_from_user(to, from, n);
+               n = __copy_from_user(to, from, n);
        else /* security hole - plug it */
                memzero(to, n);
        return n;
 }
 
-static inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
-{
-       return __arch_copy_from_user(to, from, n);
-}
-
 static inline unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
 {
        if (access_ok(VERIFY_WRITE, to, n))
-               n = __arch_copy_to_user(to, from, n);
+               n = __copy_to_user(to, from, n);
        return n;
 }
 
-static inline unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
-{
-       return __arch_copy_to_user(to, from, n);
-}
-
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
 
-static inline unsigned long clear_user (void __user *to, unsigned long n)
+static inline unsigned long clear_user(void __user *to, unsigned long n)
 {
        if (access_ok(VERIFY_WRITE, to, n))
-               n = __arch_clear_user(to, n);
+               n = __clear_user(to, n);
        return n;
 }
 
-static inline unsigned long __clear_user (void __user *to, unsigned long n)
-{
-       return __arch_clear_user(to, n);
-}
-
-static inline long strncpy_from_user (char *dst, const char __user *src, long count)
+static inline long strncpy_from_user(char *dst, const char __user *src, long count)
 {
        long res = -EFAULT;
        if (access_ok(VERIFY_READ, src, 1))
-               res = __arch_strncpy_from_user(dst, src, count);
+               res = __strncpy_from_user(dst, src, count);
        return res;
 }
 
-static inline long __strncpy_from_user (char *dst, const char __user *src, long count)
-{
-       return __arch_strncpy_from_user(dst, src, count);
-}
-
 #define strlen_user(s) strnlen_user(s, ~0UL >> 1)
 
 static inline long strnlen_user(const char __user *s, long n)
@@ -420,7 +436,7 @@ static inline long strnlen_user(const char __user *s, long n)
        unsigned long res = 0;
 
        if (__addr_ok(s))
-               res = __arch_strnlen_user(s, n);
+               res = __strnlen_user(s, n);
 
        return res;
 }
index 9e6f7ca9f5ae3623f9eed2bb11e6e236dc561fb5..bf65e9f4525d04f78dacff51b229ee7f767b0432 100644 (file)
@@ -35,6 +35,17 @@ struct ucontext {
  * bytes, to prevent unpredictable padding in the signal frame.
  */
 
+#ifdef CONFIG_CRUNCH
+#define CRUNCH_MAGIC           0x5065cf03
+#define CRUNCH_STORAGE_SIZE    (CRUNCH_SIZE + 8)
+
+struct crunch_sigframe {
+       unsigned long   magic;
+       unsigned long   size;
+       struct crunch_state     storage;
+} __attribute__((__aligned__(8)));
+#endif
+
 #ifdef CONFIG_IWMMXT
 /* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */
 #define IWMMXT_MAGIC           0x12ef842a
@@ -74,6 +85,9 @@ struct vfp_sigframe
  * one of these.
  */
 struct aux_sigframe {
+#ifdef CONFIG_CRUNCH
+       struct crunch_sigframe  crunch;
+#endif
 #ifdef CONFIG_IWMMXT
        struct iwmmxt_sigframe  iwmmxt;
 #endif
index 341536a234e9ccd4e62cd4de8174821c450f4b5c..298066020af212a98a26c15b82b65401832ac151 100644 (file)
@@ -1,7 +1,5 @@
 #ifndef _ASM_HW_IRQ_H
 #define _ASM_HW_IRQ_H
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
-
 #endif
 
index 4b338792218b045ce9593af9f5bac2329f686986..998cce9f3200308dd6c87c5f23276e13709ae724 100644 (file)
@@ -1,11 +1,6 @@
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
 
-/*
- * IRQ line status macro IRQ_PER_CPU is used
- */
-#define ARCH_HAS_IRQ_PER_CPU
-
 #include <asm/arch/irq.h>
 
 static inline int irq_canonicalize(int irq)
index 845cb67ad8ea5d40bcb707462d30879255247b81..8ceab7bcd8b4f229f45536f8208e5394c99e9695 100644 (file)
        __ret;                                          \
 })
 
+#ifdef CONFIG_SMP
+# define WARN_ON_SMP(x)                        WARN_ON(x)
+#else
+# define WARN_ON_SMP(x)                        do { } while (0)
+#endif
+
 #endif
index 9d11550b481810e6f459598dcac969187c1f6a4b..db5a3732f1065a79dde1660e8149d70e2a18091b 100644 (file)
                VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;               \
        }                                                               \
                                                                        \
+       /* Kernel symbol table: Normal unused symbols */                \
+       __ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {  \
+               VMLINUX_SYMBOL(__start___ksymtab_unused) = .;           \
+               *(__ksymtab_unused)                                     \
+               VMLINUX_SYMBOL(__stop___ksymtab_unused) = .;            \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: GPL-only unused symbols */              \
+       __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
+               VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .;       \
+               *(__ksymtab_unused_gpl)                                 \
+               VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .;        \
+       }                                                               \
+                                                                       \
        /* Kernel symbol table: GPL-future-only symbols */              \
        __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
                VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;       \
                VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;               \
        }                                                               \
                                                                        \
+       /* Kernel symbol table: Normal unused symbols */                \
+       __kcrctab_unused  : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) {  \
+               VMLINUX_SYMBOL(__start___kcrctab_unused) = .;           \
+               *(__kcrctab_unused)                                     \
+               VMLINUX_SYMBOL(__stop___kcrctab_unused) = .;            \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: GPL-only unused symbols */              \
+       __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
+               VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .;       \
+               *(__kcrctab_unused_gpl)                                 \
+               VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .;        \
+       }                                                               \
+                                                                       \
        /* Kernel symbol table: GPL-future-only symbols */              \
        __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
                VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;       \
index e7252c216ca81cc8d6543f51b51fa1f8a216d194..b1bc7b1b64b0e304d13f907e4d5cd607417bdfee 100644 (file)
@@ -7,8 +7,6 @@
 #include <linux/nodemask.h>
 #include <linux/percpu.h>
 
-#include <asm/node.h>
-
 struct i386_cpu {
        struct cpu cpu;
 };
index 4153d80e4d2b86535a6e55a6e72a30ba7b5b5699..1eac92cb5b161744c463eec3ccd7d84395cc02f0 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/processor.h>
 #include <asm/system.h>                /* for savesegment */
 #include <asm/auxvec.h>
+#include <asm/desc.h>
 
 #include <linux/utsname.h>
 
@@ -129,15 +130,41 @@ extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct
 #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
 #define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs)
 
-#define VSYSCALL_BASE  (__fix_to_virt(FIX_VSYSCALL))
-#define VSYSCALL_EHDR  ((const struct elfhdr *) VSYSCALL_BASE)
-#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall)
+#define VDSO_HIGH_BASE         (__fix_to_virt(FIX_VDSO))
+#define VDSO_BASE              ((unsigned long)current->mm->context.vdso)
+
+#ifdef CONFIG_COMPAT_VDSO
+# define VDSO_COMPAT_BASE      VDSO_HIGH_BASE
+# define VDSO_PRELINK          VDSO_HIGH_BASE
+#else
+# define VDSO_COMPAT_BASE      VDSO_BASE
+# define VDSO_PRELINK          0
+#endif
+
+#define VDSO_COMPAT_SYM(x) \
+               (VDSO_COMPAT_BASE + (unsigned long)(x) - VDSO_PRELINK)
+
+#define VDSO_SYM(x) \
+               (VDSO_BASE + (unsigned long)(x) - VDSO_PRELINK)
+
+#define VDSO_HIGH_EHDR         ((const struct elfhdr *) VDSO_HIGH_BASE)
+#define VDSO_EHDR              ((const struct elfhdr *) VDSO_COMPAT_BASE)
+
 extern void __kernel_vsyscall;
 
+#define VDSO_ENTRY             VDSO_SYM(&__kernel_vsyscall)
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+                                       int executable_stack);
+
+extern unsigned int vdso_enabled;
+
 #define ARCH_DLINFO                                            \
-do {                                                           \
-               NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY);        \
-               NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE);    \
+do if (vdso_enabled) {                                         \
+               NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY);            \
+               NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_COMPAT_BASE); \
 } while (0)
 
 /*
@@ -148,15 +175,15 @@ do {                                                              \
  * Dumping its extra ELF program headers includes all the other information
  * a debugger needs to easily find how the vsyscall DSO was being used.
  */
-#define ELF_CORE_EXTRA_PHDRS           (VSYSCALL_EHDR->e_phnum)
+#define ELF_CORE_EXTRA_PHDRS           (VDSO_HIGH_EHDR->e_phnum)
 #define ELF_CORE_WRITE_EXTRA_PHDRS                                           \
 do {                                                                         \
        const struct elf_phdr *const vsyscall_phdrs =                         \
-               (const struct elf_phdr *) (VSYSCALL_BASE                      \
-                                          + VSYSCALL_EHDR->e_phoff);         \
+               (const struct elf_phdr *) (VDSO_HIGH_BASE                     \
+                                          + VDSO_HIGH_EHDR->e_phoff);    \
        int i;                                                                \
        Elf32_Off ofs = 0;                                                    \
-       for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
+       for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) {               \
                struct elf_phdr phdr = vsyscall_phdrs[i];                     \
                if (phdr.p_type == PT_LOAD) {                                 \
                        BUG_ON(ofs != 0);                                     \
@@ -174,10 +201,10 @@ do {                                                                            \
 #define ELF_CORE_WRITE_EXTRA_DATA                                            \
 do {                                                                         \
        const struct elf_phdr *const vsyscall_phdrs =                         \
-               (const struct elf_phdr *) (VSYSCALL_BASE                      \
-                                          + VSYSCALL_EHDR->e_phoff);         \
+               (const struct elf_phdr *) (VDSO_HIGH_BASE                     \
+                                          + VDSO_HIGH_EHDR->e_phoff);    \
        int i;                                                                \
-       for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
+       for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) {               \
                if (vsyscall_phdrs[i].p_type == PT_LOAD)                      \
                        DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr,        \
                                   PAGE_ALIGN(vsyscall_phdrs[i].p_memsz));    \
index f7e068f4d2f98d7cdb8c5198cd26c1796bb3d9dc..a48cc3f7ccc688a725595e46bb21c6e2fe7fb0ad 100644 (file)
@@ -51,7 +51,7 @@
  */
 enum fixed_addresses {
        FIX_HOLE,
-       FIX_VSYSCALL,
+       FIX_VDSO,
 #ifdef CONFIG_X86_LOCAL_APIC
        FIX_APIC_BASE,  /* local (CPU) APIC) -- required for SMP or not */
 #endif
@@ -115,14 +115,6 @@ extern void __set_fixmap (enum fixed_addresses idx,
 #define __fix_to_virt(x)       (FIXADDR_TOP - ((x) << PAGE_SHIFT))
 #define __virt_to_fix(x)       ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
 
-/*
- * This is the range that is readable by user mode, and things
- * acting like user mode such as get_user_pages.
- */
-#define FIXADDR_USER_START     (__fix_to_virt(FIX_VSYSCALL))
-#define FIXADDR_USER_END       (FIXADDR_USER_START + PAGE_SIZE)
-
-
 extern void __this_fixmap_does_not_exist(void);
 
 /*
index a4c0a5a9ffd84cd4a5c18eab814dc89f08cb69f8..87e5a351d8812b369bf1fc88187214d947d87fa9 100644 (file)
@@ -69,14 +69,4 @@ extern atomic_t irq_mis_count;
 
 #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
 
-#if defined(CONFIG_X86_IO_APIC)
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
-       if (IO_APIC_IRQ(i))
-               send_IPI_self(IO_APIC_VECTOR(i));
-}
-#else
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
-#endif
-
 #endif /* _ASM_HW_IRQ_H */
index b92d6d9a4d3ced6b7785a9f4d9bdbdf0d124e427..33f700ef68316048cdb049f436d187d57854295a 100644 (file)
@@ -1,5 +1,8 @@
 /* Hook to call BIOS initialisation function */
 
+extern unsigned long sgivwfb_mem_phys;
+extern unsigned long sgivwfb_mem_size;
+
 /* no action for visws */
 
 #define ARCH_SETUP
index f431a0b86d4c46669e49b0fe4811a64017a27385..8358dd3df7aa22c1eb5bd4637f68b47b5509cd76 100644 (file)
@@ -12,6 +12,7 @@ typedef struct {
        int size;
        struct semaphore sem;
        void *ldt;
+       void *vdso;
 } mm_context_t;
 
 #endif
diff --git a/include/asm-i386/node.h b/include/asm-i386/node.h
deleted file mode 100644 (file)
index e13c6ff..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _ASM_I386_NODE_H_
-#define _ASM_I386_NODE_H_
-
-#include <linux/device.h>
-#include <linux/mmzone.h>
-#include <linux/node.h>
-#include <linux/topology.h>
-#include <linux/nodemask.h>
-
-struct i386_node {
-       struct node node;
-};
-extern struct i386_node node_devices[MAX_NUMNODES];
-
-static inline int arch_register_node(int num){
-       int p_node;
-       struct node *parent = NULL;
-
-       if (!node_online(num))
-               return 0;
-       p_node = parent_node(num);
-
-       if (p_node != num)
-               parent = &node_devices[p_node].node;
-
-       return register_node(&node_devices[num].node, num, parent);
-}
-
-#endif /* _ASM_I386_NODE_H_ */
index e3a552fa5538744bd578d6351c8c23756774c782..f5bf544c729a373aa4ec1832aa9fa3cd55a13800 100644 (file)
@@ -96,6 +96,8 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 
 #ifndef __ASSEMBLY__
 
+struct vm_area_struct;
+
 /*
  * This much address space is reserved for vmalloc() and iomap()
  * as well as fixmap mappings.
@@ -139,6 +141,7 @@ extern int page_is_ram(unsigned long pagenr);
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
+#define __HAVE_ARCH_GATE_AREA 1
 #endif /* __KERNEL__ */
 
 #endif /* _I386_PAGE_H */
index 55ea992da32954c2bdd1aca5c5c902f7b4c3b02a..b32346d62e1039d956c919b190836f2ab0217ef1 100644 (file)
@@ -71,8 +71,12 @@ struct cpuinfo_x86 {
        cpumask_t llc_shared_map;       /* cpus sharing the last level cache */
 #endif
        unsigned char x86_max_cores;    /* cpuid returned max cores value */
-       unsigned char booted_cores;     /* number of cores as seen by OS */
        unsigned char apicid;
+#ifdef CONFIG_SMP
+       unsigned char booted_cores;     /* number of cores as seen by OS */
+       __u8 phys_proc_id;              /* Physical processor id. */
+       __u8 cpu_core_id;               /* Core id */
+#endif
 } __attribute__((__aligned__(SMP_CACHE_BYTES)));
 
 #define X86_VENDOR_INTEL 0
@@ -104,8 +108,6 @@ extern struct cpuinfo_x86 cpu_data[];
 #define current_cpu_data boot_cpu_data
 #endif
 
-extern int phys_proc_id[NR_CPUS];
-extern int cpu_core_id[NR_CPUS];
 extern int cpu_llc_id[NR_CPUS];
 extern char ignore_fpu_irq;
 
index fdbc7f422ea5501ec586eabed02b349072e0184b..2833fa2c0dd0e6d5a54b5b6539123533f9c04855 100644 (file)
@@ -37,6 +37,7 @@ struct thread_info {
                                                   0-0xBFFFFFFF for user-thead
                                                   0-0xFFFFFFFF for kernel-thread
                                                */
+       void                    *sysenter_return;
        struct restart_block    restart_block;
 
        unsigned long           previous_esp;   /* ESP of the previous stack in case
@@ -83,17 +84,15 @@ struct thread_info {
 #define init_stack             (init_thread_union.stack)
 
 
+/* how to get the current stack pointer from C */
+register unsigned long current_stack_pointer asm("esp") __attribute_used__;
+
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {
-       struct thread_info *ti;
-       __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(THREAD_SIZE - 1)));
-       return ti;
+       return (struct thread_info *)(current_stack_pointer & ~(THREAD_SIZE - 1));
 }
 
-/* how to get the current stack pointer from C */
-register unsigned long current_stack_pointer asm("esp") __attribute_used__;
-
 /* thread information allocation */
 #ifdef CONFIG_DEBUG_STACK_USAGE
 #define alloc_thread_info(tsk)                                 \
index b94e5eeef917ea92d9f7339593e1bda8dcc3bafd..6adbd9b1ae881121e9f377a121ec0c4e9355361c 100644 (file)
 #define _ASM_I386_TOPOLOGY_H
 
 #ifdef CONFIG_X86_HT
-#define topology_physical_package_id(cpu)                              \
-       (phys_proc_id[cpu] == BAD_APICID ? -1 : phys_proc_id[cpu])
-#define topology_core_id(cpu)                                          \
-       (cpu_core_id[cpu] == BAD_APICID ? 0 : cpu_core_id[cpu])
+#define topology_physical_package_id(cpu)      (cpu_data[cpu].phys_proc_id)
+#define topology_core_id(cpu)                  (cpu_data[cpu].cpu_core_id)
 #define topology_core_siblings(cpu)            (cpu_core_map[cpu])
 #define topology_thread_siblings(cpu)          (cpu_sibling_map[cpu])
 #endif
@@ -114,4 +112,9 @@ extern unsigned long node_remap_size[];
 
 extern cpumask_t cpu_coregroup_map(int cpu);
 
+#ifdef CONFIG_SMP
+#define mc_capable()   (boot_cpu_data.x86_max_cores > 1)
+#define smt_capable()  (smp_num_siblings > 1)
+#endif
+
 #endif /* _ASM_I386_TOPOLOGY_H */
index d480f2e38215d69df898f89e11519f3c00b9dc85..69f0f1df67220edd0bc7bfe0b2148c6038b86e05 100644 (file)
@@ -78,8 +78,8 @@ static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
        return user_mode_vm(&info->regs);
 #else
        return info->regs.eip < PAGE_OFFSET
-              || (info->regs.eip >= __fix_to_virt(FIX_VSYSCALL)
-                   && info->regs.eip < __fix_to_virt(FIX_VSYSCALL) + PAGE_SIZE)
+              || (info->regs.eip >= __fix_to_virt(FIX_VDSO)
+                   && info->regs.eip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE)
               || info->regs.esp < PAGE_OFFSET;
 #endif
 }
index ea8b8c407ab4a210f50b055c2030cb34222fdca0..27f9df6b914539401c26421ce0bb38d970ef0081 100644 (file)
@@ -97,8 +97,7 @@ extern int reserve_irq_vector (int vector);
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
 extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
 
-static inline void
-hw_resend_irq (struct hw_interrupt_type *h, unsigned int vector)
+static inline void ia64_resend_irq(unsigned int vector)
 {
        platform_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0);
 }
index dbe86c0bbce5f896f25e4934228ac2c36228227a..79479e2c6966b0cb468db6f348538e8b0e19d32f 100644 (file)
 #define NR_IRQS                256
 #define NR_IRQ_VECTORS NR_IRQS
 
-/*
- * IRQ line status macro IRQ_PER_CPU is used
- */
-#define ARCH_HAS_IRQ_PER_CPU
-
 static __inline__ int
 irq_canonicalize (int irq)
 {
index a140310bf84dcb4120980b883965a9ea9260a847..2fb337b0e9b786486508a6611c3e6e098ea58781 100644 (file)
@@ -46,6 +46,18 @@ struct ia64_node_data {
  */
 #define NODE_DATA(nid)         (local_node_data->pg_data_ptrs[nid])
 
+/*
+ * LOCAL_DATA_ADDR - This is to calculate the address of other node's
+ *                  "local_node_data" at hot-plug phase. The local_node_data
+ *                  is pointed by per_cpu_page. Kernel usually use it for
+ *                  just executing cpu. However, when new node is hot-added,
+ *                  the addresses of local data for other nodes are necessary
+ *                  to update all of them.
+ */
+#define LOCAL_DATA_ADDR(pgdat)                         \
+       ((struct ia64_node_data *)((u64)(pgdat) +       \
+                                  L1_CACHE_ALIGN(sizeof(struct pglist_data))))
+
 #endif /* CONFIG_NUMA */
 
 #endif /* _ASM_IA64_NODEDATA_H */
index cd490b20d59268cc9723b7b23dd036d1c215d078..bd4452bda357b8e58837daf43093be52d147bade 100644 (file)
@@ -85,6 +85,7 @@
 #define  SN_SAL_GET_PROM_FEATURE_SET              0x02000065
 #define  SN_SAL_SET_OS_FEATURE_SET                0x02000066
 #define  SN_SAL_INJECT_ERROR                      0x02000067
+#define  SN_SAL_SET_CPU_NUMBER                    0x02000068
 
 /*
  * Service-specific constants
@@ -1150,4 +1151,13 @@ sn_inject_error(u64 paddr, u64 *data, u64 *ecc)
        local_irq_restore(irq_flags);
        return ret_stuff.status;
 }
+
+static inline int
+ia64_sn_set_cpu_number(int cpu)
+{
+       struct ia64_sal_retval rv;
+
+       SAL_CALL_NOLOCK(rv, SN_SAL_SET_CPU_NUMBER, cpu, 0, 0, 0, 0, 0, 0);
+       return rv.status;
+}
 #endif /* _ASM_IA64_SN_SN_SAL_H */
index 616b5ed2aa7277e12885e6e35805d4fcacf748d9..937c212575239f3ec9ee9526e2c989289669f967 100644 (file)
@@ -112,6 +112,7 @@ void build_cpu_to_node_map(void);
 #define topology_core_id(cpu)                  (cpu_data(cpu)->core_id)
 #define topology_core_siblings(cpu)            (cpu_core_map[cpu])
 #define topology_thread_siblings(cpu)          (cpu_sibling_map[cpu])
+#define smt_capable()                          (smp_num_siblings > 1)
 #endif
 
 #include <asm-generic/topology.h>
index 8d7e9d0e09e876329089bc7401c662430dc78ae2..7138537cda03017c2bce4cb15f1a7a7380a82a2a 100644 (file)
@@ -1,9 +1,4 @@
 #ifndef _ASM_M32R_HW_IRQ_H
 #define _ASM_M32R_HW_IRQ_H
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
-       /* Nothing to do */
-}
-
 #endif /* _ASM_M32R_HW_IRQ_H */
index 3fdc79f06d501a44cfe60045588f7c072968cf4f..bdc1a4ac4fe956ebdfdfe12746c3a0932a844214 100644 (file)
@@ -52,7 +52,7 @@ type name(void) \
    __asm__ __volatile__ ("trap #2" \
                          : "=g" (__res) \
                          : "0" (__res) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
@@ -64,7 +64,7 @@ type name(atype a) \
    __asm__ __volatile__ ("trap #2" \
                          : "=g" (__res) \
                          : "0" (__res), "d" (__a) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
@@ -77,7 +77,7 @@ type name(atype a, btype b) \
    __asm__ __volatile__ ("trap #2" \
                          : "=g" (__res) \
                          : "0" (__res), "d" (__a), "d" (__b) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
@@ -92,7 +92,7 @@ type name(atype a, btype b, ctype c) \
                          : "=g" (__res) \
                          : "0" (__res), "d" (__a), "d" (__b), \
                            "d" (__c) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
@@ -108,7 +108,7 @@ type name(atype a, btype b, ctype c, dtype d) \
                          : "=g" (__res) \
                          : "0" (__res), "d" (__a), "d" (__b), \
                            "d" (__c), "d" (__d) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
@@ -125,7 +125,7 @@ type name(atype a, btype b, ctype c, dtype d, etype e) \
                          : "=g" (__res) \
                          : "0" (__res), "d" (__a), "d" (__b), \
                            "d" (__c), "d" (__d), "d" (__e) \
-                         : "%d0"); \
+                         ); \
    __bsc_return(type,__res); \
 }
 
index 1e19c457de7de9750f15ae842887aad8f4faf96a..47258e86e8c4a69e996504d52e34abfcea3524a4 100644 (file)
@@ -46,11 +46,9 @@ struct pt_regs {
 #else
   unsigned short sr;
   unsigned long  pc;
-#ifndef NO_FORMAT_VEC
   unsigned format :  4; /* frame format specifier */
   unsigned vector : 12; /* vector offset */
 #endif
-#endif
 };
 
 /*
index 2c42f6b00a49e2f171d09043395e35d39781e947..92e62ef711edbac3d7aeedd7d73ffcccfc705fa4 100644 (file)
        ori     \reg, \reg, TCSTATUS_IXMT
        xori    \reg, \reg, TCSTATUS_IXMT
        mtc0    \reg, CP0_TCSTATUS
-       ehb
+       _ehb
        .endm
 
        .macro  local_irq_disable reg=t0
        mfc0    \reg, CP0_TCSTATUS
        ori     \reg, \reg, TCSTATUS_IXMT
        mtc0    \reg, CP0_TCSTATUS
-       ehb
+       _ehb
        .endm
 #else
        .macro  local_irq_enable reg=t0
index 881ce1f9803da703f0b8681ed0459f01c7c67dc3..44285a9d55204c767fc63d0e972fe6fff94cdca8 100644 (file)
 # endif
 #endif
 
-#ifdef CONFIG_CPU_MIPSR2
-# if defined(CONFIG_CPU_MIPSR2_IRQ_VI) && !defined(cpu_has_vint)
-#  define cpu_has_vint         (cpu_data[0].options & MIPS_CPU_VINT)
-# else
-#  define cpu_has_vint                 0
-# endif
-# if defined(CONFIG_CPU_MIPSR2_IRQ_EI) && !defined(cpu_has_veic)
-#  define cpu_has_veic         (cpu_data[0].options & MIPS_CPU_VEIC)
-# else
-#  define cpu_has_veic                 0
-# endif
-#else
+#if defined(CONFIG_CPU_MIPSR2_IRQ_VI) && !defined(cpu_has_vint)
+# define cpu_has_vint          (cpu_data[0].options & MIPS_CPU_VINT)
+#elif !defined(cpu_has_vint)
 # define cpu_has_vint                  0
+#endif
+
+#if defined(CONFIG_CPU_MIPSR2_IRQ_EI) && !defined(cpu_has_veic)
+# define cpu_has_veic          (cpu_data[0].options & MIPS_CPU_VEIC)
+#elif !defined(cpu_has_veic)
 # define cpu_has_veic                  0
 #endif
 
index 1cadefbbc0373b256d5090fa48bad770770e2c3d..6959bdb59310b096ec7797e0a31c78fde5aa9afc 100644 (file)
@@ -69,7 +69,11 @@ extern void __set_fixmap (enum fixed_addresses idx,
  * the start of the fixmap, and leave one page empty
  * at the top of mem..
  */
+#if defined(CONFIG_CPU_TX39XX) || defined(CONFIG_CPU_TX49XX)
+#define FIXADDR_TOP    (0xff000000UL - 0x2000)
+#else
 #define FIXADDR_TOP    (0xffffe000UL)
+#endif
 #define FIXADDR_SIZE   (__end_of_fixed_addresses << PAGE_SHIFT)
 #define FIXADDR_START  (FIXADDR_TOP - FIXADDR_SIZE)
 
index 66943c451c1dbcb196db60f042cd2a33928d7254..25f5e8a4177d1378fb60645483a4e364c1e879c1 100644 (file)
  * Use a macro for ehb unless explicit support for MIPSR2 is enabled
  */
 
-#define irq_enable_hazard
+#define irq_enable_hazard                                              \
        _ehb
 
-#define irq_disable_hazard
+#define irq_disable_hazard                                             \
        _ehb
 
 #elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000)
index c854d017c0e5b2090af5b3bdadc56751b839a504..458d9fdc76bf2eed4372a0993dd0ebb0f1b08baa 100644 (file)
@@ -19,9 +19,9 @@ extern void init_8259A(int aeoi);
 
 extern atomic_t irq_err_count;
 
-/* This may not be apropriate for all machines, we'll see ...  */
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
-}
+/*
+ * interrupt-retrigger: NOP for now. This may not be apropriate for all
+ * machines, we'll see ...
+ */
 
 #endif /* __ASM_HW_IRQ_H */
index d35c61776a0249d5620a8a70a8033b15735f48fc..896550bad3229cbd388fa8ce9705129ecdf91ca4 100644 (file)
@@ -76,4 +76,8 @@ extern int setup_irq_smtc(unsigned int irq, struct irqaction * new,
                           unsigned long hwmask);
 #endif /* CONFIG_MIPS_MT_SMTC */
 
+#ifdef CONFIG_SMP
+#define ARCH_HAS_IRQ_PER_CPU
+#endif
+
 #endif /* _ASM_IRQ_H */
index d7cbacdd21fe57107b9dc925dae5526010bf7c32..1bd4e27caf6b70ee4ecbc1b2df29846e124e9969 100644 (file)
@@ -512,7 +512,7 @@ typedef struct      psc_smb {
 
 /* Transmit register control.
 */
-#define PSC_SMBTXRX_RSR                (1 << 30)
+#define PSC_SMBTXRX_RSR                (1 << 28)
 #define PSC_SMBTXRX_STP                (1 << 29)
 #define PSC_SMBTXRX_DATAMASK   (0xff)
 
index 083d9c512a04914c6520f54603c310af932a5213..e994b0c012279a316693e403b4f94d80ea522c4d 100644 (file)
@@ -4,10 +4,4 @@
 
 #define NR_IRQS        256
 
-#ifdef CONFIG_SMP
-
-#define ARCH_HAS_IRQ_PER_CPU
-
-#endif
-
 #endif /* __ASM_MACH_MIPS_IRQ_H */
index 673977901ed3e65b490031bbd2ecb38fef279c71..9192d76c133dc444d49148a3ebb1d5bfd3eade74 100644 (file)
@@ -1459,7 +1459,8 @@ static inline void __emt(unsigned int previous)
 static inline void __ehb(void)
 {
        __asm__ __volatile__(
-       "       ehb                                                     \n");
+       "       .set    mips32r2                                        \n"
+       "       ehb                                                     \n"             "       .set    mips0                                           \n");
 }
 
 /*
index f7d530f306f26bab1002b6220ef1bb395fb423fd..099677774d71b73fbfb1b649c9c4de15116ec055 100644 (file)
@@ -5,6 +5,8 @@
 #ifndef _IOC3_H
 #define _IOC3_H
 
+#include <linux/types.h>
+
 /* SUPERIO uart register map */
 typedef volatile struct ioc3_uartregs {
        union {
index 52238e65af8e43227f304c35d4d2fcb6d3321b35..b63cd0655b3d554d2145acd134d2815c67e69f22 100644 (file)
@@ -602,7 +602,7 @@ typedef struct klcpu_s {                          /* CPU */
 
 typedef struct klhub_s {                       /* HUB */
        klinfo_t        hub_info;
-       uint            hub_flags;              /* PCFG_HUB_xxx flags */
+       unsigned int            hub_flags;              /* PCFG_HUB_xxx flags */
        klport_t        hub_port;               /* hub is connected to this */
        nic_t           hub_box_nic;            /* nic of containing box */
        klconf_off_t    hub_mfg_nic;            /* MFG NIC string */
@@ -611,7 +611,7 @@ typedef struct klhub_s {                    /* HUB */
 
 typedef struct klhub_uart_s {                  /* HUB */
        klinfo_t        hubuart_info;
-       uint            hubuart_flags;          /* PCFG_HUB_xxx flags */
+       unsigned int            hubuart_flags;          /* PCFG_HUB_xxx flags */
        nic_t           hubuart_box_nic;        /* nic of containing box */
 } klhub_uart_t ;
 
@@ -710,7 +710,7 @@ typedef struct klvmed_s {                          /* VME DEVICE - VME BOARD */
 /* XXX - Don't we need the number of ports here?!? */
 typedef struct klrou_s {                          /* ROUTER */
        klinfo_t        rou_info ;
-       uint            rou_flags ;           /* PCFG_ROUTER_xxx flags */
+       unsigned int            rou_flags ;           /* PCFG_ROUTER_xxx flags */
        nic_t           rou_box_nic ;         /* nic of the containing module */
        klport_t        rou_port[MAX_ROUTER_PORTS + 1] ; /* array index 1 to 6 */
        klconf_off_t    rou_mfg_nic ;     /* MFG NIC string */
@@ -733,8 +733,8 @@ typedef struct klgfx_s {            /* GRAPHICS Device */
        klinfo_t        gfx_info;
        klconf_off_t    old_gndevs;     /* for compatibility with older proms */
        klconf_off_t    old_gdoff0;     /* for compatibility with older proms */
-       uint            cookie;         /* for compatibility with older proms */
-       uint            moduleslot;
+       unsigned int            cookie;         /* for compatibility with older proms */
+       unsigned int            moduleslot;
        struct klgfx_s  *gfx_next_pipe;
        graphics_t      gfx_specific;
        klconf_off_t    pad0;           /* for compatibility with older proms */
index 513aa5133830e59aa0f0dfa9c1162accbbbefc72..158a4cd12e460a0dfb7a4a5ee56fc25ee28008f2 100644 (file)
                mfc0    v0, CP0_TCSTATUS
                ori     v0, TCSTATUS_IXMT
                mtc0    v0, CP0_TCSTATUS
-               ehb
+               _ehb
                DMT     5                               # dmt a1
                jal     mips_ihb
 #endif /* CONFIG_MIPS_MT_SMTC */
  * restore TCStatus.IXMT.
  */
                LONG_L  v1, PT_TCSTATUS(sp)
-               ehb
+               _ehb
                mfc0    v0, CP0_TCSTATUS
                andi    v1, TCSTATUS_IXMT
                /* We know that TCStatua.IXMT should be set from above */
                xori    v0, v0, TCSTATUS_IXMT
                or      v0, v0, v1
                mtc0    v0, CP0_TCSTATUS
-               ehb
+               _ehb
                andi    a1, a1, VPECONTROL_TE
                beqz    a1, 1f
                emt
                /* Clear TKSU, leave IXMT */
                xori    t0, 0x00001800
                mtc0    t0, CP0_TCSTATUS
-               ehb
+               _ehb
                /* We need to leave the global IE bit set, but clear EXL...*/
                mfc0    t0, CP0_STATUS
                ori     t0, ST0_EXL | ST0_ERL
                 * and enable interrupts only for the
                 * current TC, using the TCStatus register.
                 */
-               ehb
+               _ehb
                mfc0    t0,CP0_TCSTATUS
                /* Fortunately CU 0 is in the same place in both registers */
                /* Set TCU0, TKSU (for later inversion) and IXMT */
                /* Clear TKSU *and* IXMT */
                xori    t0, 0x00001c00
                mtc0    t0, CP0_TCSTATUS
-               ehb
+               _ehb
                /* We need to leave the global IE bit set, but clear EXL...*/
                mfc0    t0, CP0_STATUS
                ori     t0, ST0_EXL
                andi    v1, v0, TCSTATUS_IXMT
                ori     v0, TCSTATUS_IXMT
                mtc0    v0, CP0_TCSTATUS
-               ehb
+               _ehb
                DMT     2                               # dmt   v0
                /*
                 * We don't know a priori if ra is "live"
                xori    t0, 0x1e
                mtc0    t0, CP0_STATUS
 #ifdef CONFIG_MIPS_MT_SMTC
-               ehb
+               _ehb
                andi    v0, v0, VPECONTROL_TE
                beqz    v0, 2f
                nop     /* delay slot */
index 8bb0bb9b2e68dbd8efb43406cf475e9e3f629f72..809f9f55bacb8f5f4b966abed542b440027f2bc2 100644 (file)
 #define __NR_unshare                   (__NR_Linux + 303)
 #define __NR_splice                    (__NR_Linux + 304)
 #define __NR_sync_file_range           (__NR_Linux + 305)
+#define __NR_tee                       (__NR_Linux + 306)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            305
+#define __NR_Linux_syscalls            306
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                305
+#define __NR_O32_Linux_syscalls                306
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_unshare                   (__NR_Linux + 262)
 #define __NR_splice                    (__NR_Linux + 263)
 #define __NR_sync_file_range           (__NR_Linux + 264)
+#define __NR_tee                       (__NR_Linux + 265)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            264
+#define __NR_Linux_syscalls            265
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         264
+#define __NR_64_Linux_syscalls         265
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_unshare                   (__NR_Linux + 266)
 #define __NR_splice                    (__NR_Linux + 267)
 #define __NR_sync_file_range           (__NR_Linux + 268)
+#define __NR_tee                       (__NR_Linux + 269)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            268
+#define __NR_Linux_syscalls            269
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                268
+#define __NR_N32_Linux_syscalls                269
 
 #ifdef __KERNEL__
 
index 3ce3440d1b0ca89fd19c3871abac0f21c646ff1f..1a7bfe699e0ccc5a33b5ab1a3c65e9b0822b780f 100644 (file)
@@ -48,6 +48,7 @@
 #define CALLEE_SAVE_FRAME_SIZE (CALLEE_REG_FRAME_SIZE + CALLEE_FLOAT_FRAME_SIZE)
 
 #ifdef CONFIG_PA20
+#define LDCW           ldcw,co
 #define BL             b,l
 # ifdef CONFIG_64BIT
 #  define LEVEL                2.0w
@@ -55,6 +56,7 @@
 #  define LEVEL                2.0
 # endif
 #else
+#define LDCW           ldcw
 #define BL             bl
 #define LEVEL          1.1
 #endif
index 289624d8b2d4681cfaed6a729a5313e07b153930..71b4eeea205a1a85eda581179fd97b46eeee0e83 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/personality.h>
 
 #define COMPAT_USER_HZ 100
 
@@ -149,4 +150,14 @@ static __inline__ void __user *compat_alloc_user_space(long len)
        return (void __user *)regs->gr[30];
 }
 
+static inline int __is_compat_task(struct task_struct *t)
+{
+       return personality(t->personality) == PER_LINUX32;
+}
+
+static inline int is_compat_task(void)
+{
+       return __is_compat_task(current);
+}
+
 #endif /* _ASM_PARISC_COMPAT_H */
index 151426e275213c23a6e1afa124fcb681a672e54e..6707f7df3921f566e044bb39ea0c31b95154f290 100644 (file)
@@ -3,15 +3,6 @@
 
 /*
  *     linux/include/asm/hw_irq.h
- *
- *     (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
- *
- *     moved some of the old arch/i386/kernel/irq.h to here. VY
- *
- *     IRQ/IPI changes taken from work by Thomas Radke
- *     <tomsoft@informatik.tu-chemnitz.de>
  */
 
-extern void hw_resend_irq(struct hw_interrupt_type *, unsigned int);
-
 #endif
index 377ba90c7d0256841568386405399164191569b4..5cae260615a22a74d14075d529a47419e9d02137 100644 (file)
 
 #define NR_IRQS                (CPU_IRQ_MAX + 1)
 
-/*
- * IRQ line status macro IRQ_PER_CPU is used
- */
-#define ARCH_HAS_IRQ_PER_CPU
-
 static __inline__ int irq_canonicalize(int irq)
 {
        return (irq == 2) ? 9 : irq;
index 08364f957e7a8811e50ed54f27ed5550e38395ff..c9b2e35326eed89eba875cd506262fdd485b21f4 100644 (file)
@@ -278,12 +278,11 @@ typedef struct {
 /* constants for OS (NVM...) */
 #define OS_ID_NONE             0       /* Undefined OS ID      */
 #define OS_ID_HPUX             1       /* HP-UX OS             */
-#define OS_ID_LINUX            OS_ID_HPUX /* just use the same value as hpux */
 #define OS_ID_MPEXL            2       /* MPE XL OS            */
 #define OS_ID_OSF              3       /* OSF OS               */
 #define OS_ID_HPRT             4       /* HP-RT OS             */
 #define OS_ID_NOVEL            5       /* NOVELL OS            */
-#define OS_ID_NT               6       /* NT OS                */
+#define OS_ID_LINUX            6       /* Linux                */
 
 
 /* constants for PDC_CHASSIS */
@@ -352,8 +351,8 @@ struct pdc_cache_cf {               /* for PDC_CACHE  (I/D-caches) */
                cc_wt   : 1,    /* 0 = WT-Dcache, 1 = WB-Dcache */
                cc_sh   : 2,    /* 0 = separate I/D-cache, else shared I/D-cache */
                cc_cst  : 3,    /* 0 = incoherent D-cache, 1=coherent D-cache */
-               cc_pad1 : 5,    /* reserved */
-               cc_assoc: 8;    /* associativity of I/D-cache */
+               cc_pad1 : 10,   /* reserved */
+               cc_hv   : 3;    /* hversion dependent */
 };
 
 struct pdc_tlb_cf {            /* for PDC_CACHE (I/D-TLB's) */
@@ -719,6 +718,7 @@ void setup_pdc(void);               /* in inventory.c */
 int pdc_add_valid(unsigned long address);
 int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
 int pdc_chassis_disp(unsigned long disp);
+int pdc_chassis_warn(unsigned long *warn);
 int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info);
 int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
                  void *iodc_data, unsigned int iodc_data_size);
@@ -732,6 +732,7 @@ int pdc_model_cpuid(unsigned long *cpu_id);
 int pdc_model_versions(unsigned long *versions, int id);
 int pdc_model_capabilities(unsigned long *capabilities);
 int pdc_cache_info(struct pdc_cache_info *cache);
+int pdc_spaceid_bits(unsigned long *space_bits);
 #ifndef CONFIG_PA20
 int pdc_btlb_info(struct pdc_btlb_info *btlb);
 int pdc_mem_map_hpa(struct pdc_memory_map *r_addr, struct pdc_module_path *mod_path);
@@ -775,6 +776,18 @@ int pdc_sti_call(unsigned long func, unsigned long flags,
 
 extern void pdc_init(void);
 
+static inline char * os_id_to_string(u16 os_id) {
+       switch(os_id) {
+       case OS_ID_NONE:        return "No OS";
+       case OS_ID_HPUX:        return "HP-UX";
+       case OS_ID_MPEXL:       return "MPE-iX";
+       case OS_ID_OSF:         return "OSF";
+       case OS_ID_HPRT:        return "HP-RT";
+       case OS_ID_NOVEL:       return "Novell Netware";
+       case OS_ID_LINUX:       return "Linux";
+       default:        return "Unknown";
+       }
+}
 #endif /* __ASSEMBLY__ */
 
 #endif /* _PARISC_PDC_H */
index b6bcc672ba8064610bf0286f9cf34988774c44e6..5066c54dae0ab422cf2dad44dff9a95007ff8f4f 100644 (file)
@@ -506,13 +506,13 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 
 /* TLB page size encoding - see table 3-1 in parisc20.pdf */
 #define _PAGE_SIZE_ENCODING_4K         0
-#define _PAGE_SIZE_ENCODING_16K        1
-#define _PAGE_SIZE_ENCODING_64K        2
+#define _PAGE_SIZE_ENCODING_16K                1
+#define _PAGE_SIZE_ENCODING_64K                2
 #define _PAGE_SIZE_ENCODING_256K       3
 #define _PAGE_SIZE_ENCODING_1M         4
 #define _PAGE_SIZE_ENCODING_4M         5
-#define _PAGE_SIZE_ENCODING_16M        6
-#define _PAGE_SIZE_ENCODING_64M        7
+#define _PAGE_SIZE_ENCODING_16M                6
+#define _PAGE_SIZE_ENCODING_64M                7
 
 #if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
 # define _PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_4K
index ca49dc91f4fca86bff592f5336ab4265a80ca497..b73626f040dace5eb8d091636be645ed564864a0 100644 (file)
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
  */
-
-/* We cannot use MFIA as it was added for PA2.0 - prumpf
-
-   At one point there were no "0f/0b" type local symbols in gas for
-   PA-RISC.  This is no longer true, but this still seems like the
-   nicest way to implement this. */
-
-#define current_text_addr() ({ void *pc; __asm__("\n\tblr 0,%0\n\tnop":"=r" (pc)); pc; })
+#ifdef CONFIG_PA20
+#define current_ia(x)  __asm__("mfia %0" : "=r"(x))
+#else /* mfia added in pa2.0 */
+#define current_ia(x)  __asm__("blr 0,%0\n\tnop" : "=r"(x))
+#endif
+#define current_text_addr() ({ void *pc; current_ia(pc); pc; })
 
 #define TASK_SIZE               (current->thread.task_size)
 #define TASK_UNMAPPED_BASE      (current->thread.map_base)
index 863876134b2ca9cce106096cfff6551689403c79..5fe2d2329ab5e7c7dbd8121351b1ea7fcef54dbc 100644 (file)
@@ -155,13 +155,14 @@ static inline void set_eiem(unsigned long val)
    type and dynamically select the 16-byte aligned int from the array
    for the semaphore.  */
 
-#define __PA_LDCW_ALIGNMENT 16
-#define __ldcw_align(a) ({ \
-  unsigned long __ret = (unsigned long) &(a)->lock[0];                 \
-  __ret = (__ret + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); \
-  (volatile unsigned int *) __ret;                                      \
+#define __PA_LDCW_ALIGNMENT    16
+#define __ldcw_align(a) ({                                     \
+       unsigned long __ret = (unsigned long) &(a)->lock[0];    \
+       __ret = (__ret + __PA_LDCW_ALIGNMENT - 1)               \
+               & ~(__PA_LDCW_ALIGNMENT - 1);                   \
+       (volatile unsigned int *) __ret;                        \
 })
-#define LDCW   "ldcw"
+#define __LDCW "ldcw"
 
 #else /*CONFIG_PA20*/
 /* From: "Jim Hull" <jim.hull of hp.com>
@@ -171,17 +172,18 @@ static inline void set_eiem(unsigned long val)
    they only require "natural" alignment (4-byte for ldcw, 8-byte for
    ldcd). */
 
-#define __PA_LDCW_ALIGNMENT 4
+#define __PA_LDCW_ALIGNMENT    4
 #define __ldcw_align(a) ((volatile unsigned int *)a)
-#define LDCW   "ldcw,co"
+#define __LDCW "ldcw,co"
 
 #endif /*!CONFIG_PA20*/
 
 /* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
-#define __ldcw(a) ({ \
-       unsigned __ret; \
-       __asm__ __volatile__(LDCW " 0(%1),%0" : "=r" (__ret) : "r" (a)); \
-       __ret; \
+#define __ldcw(a) ({                                           \
+       unsigned __ret;                                         \
+       __asm__ __volatile__(__LDCW " 0(%1),%0"                 \
+               : "=r" (__ret) : "r" (a));                      \
+       __ret;                                                  \
 })
 
 #ifdef CONFIG_SMP
index f6c417c8c484a8965eee6ac6cfd175d45a82c8d4..d973e8b3466ca805afbdf52a846211434f2e8269 100644 (file)
@@ -172,7 +172,11 @@ struct exception_data {
 /*
  * The "__put_user/kernel_asm()" macros tell gcc they read from memory
  * instead of writing. This is because they do not write to any memory
- * gcc knows about, so there are no aliasing issues.
+ * gcc knows about, so there are no aliasing issues. These macros must
+ * also be aware that "fixup_put_user_skip_[12]" are executed in the
+ * context of the fault, and any registers used there must be listed
+ * as clobbers. In this case only "r1" is used by the current routines.
+ * r8/r9 are already listed as err/val.
  */
 
 #ifdef __LP64__
@@ -183,7 +187,8 @@ struct exception_data {
                "\t.dword\t1b,fixup_put_user_skip_1\n"      \
                "\t.previous"                               \
                : "=r"(__pu_err)                            \
-               : "r"(ptr), "r"(x), "0"(__pu_err))
+               : "r"(ptr), "r"(x), "0"(__pu_err)           \
+               : "r1")
 
 #define __put_user_asm(stx,x,ptr)                           \
        __asm__ __volatile__ (                              \
index 12b867238a4751438fc76b3ac37132fd37f5f938..27bcfad1c3e337cf3642245c3430dba14202ccb4 100644 (file)
 
 #define SYS_ify(syscall_name)   __NR_##syscall_name
 
-/* Assume all syscalls are done from PIC code just to be
- * safe. The worst case scenario is that you lose a register
- * and save/restore r19 across the syscall. */
-#define PIC
-
 #ifndef ASM_LINE_SEP
 # define ASM_LINE_SEP ;
 #endif
index fab41c280aa1993697eff52dfebf3b5de2129a6e..1ba3c9983614dc9232f4dd921b32abc7e20f4a92 100644 (file)
@@ -117,38 +117,30 @@ extern void do_cpu_ftr_fixups(unsigned long offset);
 #define CPU_FTR_PPC_LE                 ASM_CONST(0x0000000000200000)
 #define CPU_FTR_REAL_LE                        ASM_CONST(0x0000000000400000)
 
+/*
+ * Add the 64-bit processor unique features in the top half of the word;
+ * on 32-bit, make the names available but defined to be 0.
+ */
 #ifdef __powerpc64__
-/* Add the 64b processor unique features in the top half of the word */
-#define CPU_FTR_SLB                    ASM_CONST(0x0000000100000000)
-#define CPU_FTR_16M_PAGE               ASM_CONST(0x0000000200000000)
-#define CPU_FTR_TLBIEL                 ASM_CONST(0x0000000400000000)
-#define CPU_FTR_NOEXECUTE              ASM_CONST(0x0000000800000000)
-#define CPU_FTR_IABR                   ASM_CONST(0x0000002000000000)
-#define CPU_FTR_MMCRA                  ASM_CONST(0x0000004000000000)
-#define CPU_FTR_CTRL                   ASM_CONST(0x0000008000000000)
-#define CPU_FTR_SMT                    ASM_CONST(0x0000010000000000)
-#define CPU_FTR_COHERENT_ICACHE                ASM_CONST(0x0000020000000000)
-#define CPU_FTR_LOCKLESS_TLBIE         ASM_CONST(0x0000040000000000)
-#define CPU_FTR_CI_LARGE_PAGE          ASM_CONST(0x0000100000000000)
-#define CPU_FTR_PAUSE_ZERO             ASM_CONST(0x0000200000000000)
-#define CPU_FTR_PURR                   ASM_CONST(0x0000400000000000)
+#define LONG_ASM_CONST(x)              ASM_CONST(x)
 #else
-/* ensure on 32b processors the flags are available for compiling but
- * don't do anything */
-#define CPU_FTR_SLB                    ASM_CONST(0x0)
-#define CPU_FTR_16M_PAGE               ASM_CONST(0x0)
-#define CPU_FTR_TLBIEL                 ASM_CONST(0x0)
-#define CPU_FTR_NOEXECUTE              ASM_CONST(0x0)
-#define CPU_FTR_IABR                   ASM_CONST(0x0)
-#define CPU_FTR_MMCRA                  ASM_CONST(0x0)
-#define CPU_FTR_CTRL                   ASM_CONST(0x0)
-#define CPU_FTR_SMT                    ASM_CONST(0x0)
-#define CPU_FTR_COHERENT_ICACHE                ASM_CONST(0x0)
-#define CPU_FTR_LOCKLESS_TLBIE         ASM_CONST(0x0)
-#define CPU_FTR_CI_LARGE_PAGE          ASM_CONST(0x0)
-#define CPU_FTR_PURR                   ASM_CONST(0x0)
+#define LONG_ASM_CONST(x)              0
 #endif
 
+#define CPU_FTR_SLB                    LONG_ASM_CONST(0x0000000100000000)
+#define CPU_FTR_16M_PAGE               LONG_ASM_CONST(0x0000000200000000)
+#define CPU_FTR_TLBIEL                 LONG_ASM_CONST(0x0000000400000000)
+#define CPU_FTR_NOEXECUTE              LONG_ASM_CONST(0x0000000800000000)
+#define CPU_FTR_IABR                   LONG_ASM_CONST(0x0000002000000000)
+#define CPU_FTR_MMCRA                  LONG_ASM_CONST(0x0000004000000000)
+#define CPU_FTR_CTRL                   LONG_ASM_CONST(0x0000008000000000)
+#define CPU_FTR_SMT                    LONG_ASM_CONST(0x0000010000000000)
+#define CPU_FTR_COHERENT_ICACHE                LONG_ASM_CONST(0x0000020000000000)
+#define CPU_FTR_LOCKLESS_TLBIE         LONG_ASM_CONST(0x0000040000000000)
+#define CPU_FTR_CI_LARGE_PAGE          LONG_ASM_CONST(0x0000100000000000)
+#define CPU_FTR_PAUSE_ZERO             LONG_ASM_CONST(0x0000200000000000)
+#define CPU_FTR_PURR                   LONG_ASM_CONST(0x0000400000000000)
+
 #ifndef __ASSEMBLY__
 
 #define CPU_FTR_PPCAS_ARCH_V2_BASE (CPU_FTR_SLB | \
index ce0f7db63c1673a1435d93e7906a27bb9cb947cd..d40359204abaa1ff38743c718a72e40ba22d3f96 100644 (file)
@@ -86,27 +86,27 @@ static inline void local_irq_save_ptr(unsigned long *flags)
 #define mask_irq(irq)                                          \
        ({                                                      \
                irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->handler && desc->handler->disable)    \
-                       desc->handler->disable(irq);            \
+               if (desc->chip && desc->chip->disable)  \
+                       desc->chip->disable(irq);               \
        })
 #define unmask_irq(irq)                                                \
        ({                                                      \
                irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->handler && desc->handler->enable)     \
-                       desc->handler->enable(irq);             \
+               if (desc->chip && desc->chip->enable)   \
+                       desc->chip->enable(irq);                \
        })
 #define ack_irq(irq)                                           \
        ({                                                      \
                irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->handler && desc->handler->ack)        \
-                       desc->handler->ack(irq);                \
+               if (desc->chip && desc->chip->ack)      \
+                       desc->chip->ack(irq);           \
        })
 
-/* Should we handle this via lost interrupts and IPIs or should we don't care like
- * we do now ? --BenH.
+/*
+ * interrupt-retrigger: should we handle this via lost interrupts and IPIs
+ * or should we not care like we do now ? --BenH.
  */
 struct hw_interrupt_type;
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HW_IRQ_H */
index a10feec29d4d4dce05685d8e112cecbbf37d8a29..eb5f33e1977a2cce8ff839eb7917f2813b4b7ce1 100644 (file)
 #define IRQ_POLARITY_POSITIVE  0x2     /* high level or low->high edge */
 #define IRQ_POLARITY_NEGATIVE  0x0     /* low level or high->low edge */
 
-/*
- * IRQ line status macro IRQ_PER_CPU is used
- */
-#define ARCH_HAS_IRQ_PER_CPU
-
 #define get_irq_desc(irq) (&irq_desc[(irq)])
 
 /* Define a way to iterate across irqs. */
index b7c6fc12cce22e0cb90da14178f9071693a82bc6..284c5a7db3ac43bb5790ed4ea7687ede2aad98b3 100644 (file)
 
 struct HvLpEvent;
 
-#define ITMaxLpQueues  8
+#define IT_LP_MAX_QUEUES       8
 
-#define NotUsed                0       // Queue will not be used by PLIC
-#define DedicatedIo    1       // Queue dedicated to IO processor specified
-#define DedicatedLp    2       // Queue dedicated to LP specified
-#define Shared         3       // Queue shared for both IO and LP
+#define IT_LP_NOT_USED         0       /* Queue will not be used by PLIC */
+#define IT_LP_DEDICATED_IO     1       /* Queue dedicated to IO processor specified */
+#define IT_LP_DEDICATED_LP     2       /* Queue dedicated to LP specified */
+#define IT_LP_SHARED           3       /* Queue shared for both IO and LP */
 
-#define LpEventStackSize       4096
-#define LpEventMaxSize         256
-#define LpEventAlign           64
+#define IT_LP_EVENT_STACK_SIZE 4096
+#define IT_LP_EVENT_MAX_SIZE   256
+#define IT_LP_EVENT_ALIGN      64
 
 struct hvlpevent_queue {
 /*
- * The xSlicCurEventPtr is the pointer to the next event stack entry
+ * The hq_current_event is the pointer to the next event stack entry
  * that will become valid.  The OS must peek at this entry to determine
  * if it is valid.  PLIC will set the valid indicator as the very last
  * store into that entry.
@@ -52,23 +52,23 @@ struct hvlpevent_queue {
  * location again.
  *
  * If the event stack fills and there are overflow events, then PLIC
- * will set the xPlicOverflowIntPending flag in which case the OS will
+ * will set the hq_overflow_pending flag in which case the OS will
  * have to fetch the additional LP events once they have drained the
  * event stack.
  *
  * The first 16-bytes are known by both the OS and PLIC.  The remainder
  * of the cache line is for use by the OS.
  */
-       u8      xPlicOverflowIntPending;// 0x00 Overflow events are pending
-       u8      xPlicStatus;            // 0x01 DedicatedIo or DedicatedLp or NotUsed
-       u16     xSlicLogicalProcIndex;  // 0x02 Logical Proc Index for correlation
-       u8      xPlicRsvd[12];          // 0x04
-       char    *xSlicCurEventPtr;      // 0x10
-       char    *xSlicLastValidEventPtr; // 0x18
-       char    *xSlicEventStackPtr;    // 0x20
-       u8      xIndex;                 // 0x28 unique sequential index.
-       u8      xSlicRsvd[3];           // 0x29-2b
-       spinlock_t      lock;
+       u8              hq_overflow_pending;    /* 0x00 Overflow events are pending */
+       u8              hq_status;              /* 0x01 DedicatedIo or DedicatedLp or NotUsed */
+       u16             hq_proc_index;          /* 0x02 Logical Proc Index for correlation */
+       u8              hq_reserved1[12];       /* 0x04 */
+       char            *hq_current_event;      /* 0x10 */
+       char            *hq_last_event;         /* 0x18 */
+       char            *hq_event_stack;        /* 0x20 */
+       u8              hq_index;               /* 0x28 unique sequential index. */
+       u8              hq_reserved2[3];        /* 0x29-2b */
+       spinlock_t      hq_lock;
 };
 
 extern struct hvlpevent_queue hvlpevent_queue;
index 5a5c3b5ab1e0236686975c0abb9d94bb9a0ef9fd..dc1574c945f8fb8a605413aa8b5b384ef2bba19a 100644 (file)
@@ -15,6 +15,8 @@
 #define KDUMP_TRAMPOLINE_START 0x0100
 #define KDUMP_TRAMPOLINE_END   0x3000
 
+#define KDUMP_MIN_TCE_ENTRIES  2048
+
 #else /* !CONFIG_CRASH_DUMP */
 
 #define PHYSICAL_START 0x0
index efe8872ec58382f78ba3807944d601e7409c80b4..8f7fd5cfec34f4c9fa0a39843ae443825f277fda 100644 (file)
@@ -112,9 +112,13 @@ static inline void crash_setup_regs(struct pt_regs *newregs,
 #ifdef __powerpc64__
 extern void kexec_smp_wait(void);      /* get and clear naca physid, wait for
                                          master to copy new code to 0 */
-extern void __init kexec_setup(void);
 extern int crashing_cpu;
 extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
+extern cpumask_t cpus_in_sr;
+static inline int kexec_sr_activated(int cpu)
+{
+       return cpu_isset(cpu,cpus_in_sr);
+}
 #endif /* __powerpc64 __ */
 
 struct kimage;
@@ -124,10 +128,13 @@ extern int default_machine_kexec_prepare(struct kimage *image);
 extern void default_machine_crash_shutdown(struct pt_regs *regs);
 
 extern void machine_kexec_simple(struct kimage *image);
+extern void crash_kexec_secondary(struct pt_regs *regs);
 extern int overlaps_crashkernel(unsigned long start, unsigned long size);
 extern void reserve_crashkernel(void);
 
 #else /* !CONFIG_KEXEC */
+static inline int kexec_sr_activated(int cpu) { return 0; }
+static inline void crash_kexec_secondary(struct pt_regs *regs) { }
 
 static inline int overlaps_crashkernel(unsigned long start, unsigned long size)
 {
index 73db1f71329db02702e323408338b272a3cd6cc5..eba133d149a793d3e7c2b05b25bb4036920a6a5b 100644 (file)
@@ -81,6 +81,8 @@ struct machdep_calls {
        void            (*tce_free)(struct iommu_table *tbl,
                                    long index,
                                    long npages);
+       unsigned long   (*tce_get)(struct iommu_table *tbl,
+                                   long index);
        void            (*tce_flush)(struct iommu_table *tbl);
        void            (*iommu_dev_setup)(struct pci_dev *dev);
        void            (*iommu_bus_setup)(struct pci_bus *bus);
index 3a5ebe229af56763ec8956573d579161aad4e4cb..c3fc7a28e3cd0cb73dd245c727cf0b3d979ee082 100644 (file)
@@ -238,7 +238,6 @@ extern int hash_huge_page(struct mm_struct *mm, unsigned long access,
                          unsigned long ea, unsigned long vsid, int local,
                          unsigned long trap);
 
-extern void htab_finish_init(void);
 extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
                             unsigned long pstart, unsigned long mode,
                             int psize);
index 8c6b1a6d944f57e8ead421ea1e42a0db0fcbecc5..083ac917bd293b4be1640d50efdad07272260117 100644 (file)
@@ -25,8 +25,13 @@ static inline void enter_lazy_tlb(struct mm_struct *mm,
 {
 }
 
+/*
+ * The proto-VSID space has 2^35 - 1 segments available for user mappings.
+ * Each segment contains 2^28 bytes.  Each context maps 2^44 bytes,
+ * so we can support 2^19-1 contexts (19 == 35 + 28 - 44).
+ */
 #define NO_CONTEXT     0
-#define MAX_CONTEXT    (0x100000-1)
+#define MAX_CONTEXT    ((1UL << 19) - 1)
 
 extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
 extern void destroy_context(struct mm_struct *mm);
index d0a6718d188bfb4dc3f85145758c06c6d1fac671..f260382739faa81018e2f63c066432da9ece11a7 100644 (file)
 #ifndef __ASM_POWERPC_MPC86xx_H__
 #define __ASM_POWERPC_MPC86xx_H__
 
-#include <linux/config.h>
 #include <asm/mmu.h>
 
 #ifdef CONFIG_PPC_86xx
 
-#ifdef CONFIG_MPC8641_HPCN
-#include <platforms/86xx/mpc8641_hpcn.h>
-#endif
-
 #define _IO_BASE        isa_io_base
 #define _ISA_MEM_BASE   isa_mem_base
 #ifdef CONFIG_PCI
index 5d2c9e6c4be2ba1483118e2de61b572ccbb2c2b1..46afd29b904e47694c1f2127b07738bf091cd075 100644 (file)
@@ -242,7 +242,7 @@ extern pgprot_t     pci_phys_mem_access_prot(struct file *file,
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
 extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
                                 const struct resource *rsrc,
-                                u64 *start, u64 *end);
+                                resource_size_t *start, resource_size_t *end);
 #endif /* CONFIG_PPC_MULTIPLATFORM || CONFIG_PPC32 */
 
 #endif /* __KERNEL__ */
index 02e213e3d69f0cc8151b96c8b0f9a4e526a187ee..a33c6acffa61f5c8bad8fbb007b1fc0dd0590563 100644 (file)
@@ -181,6 +181,9 @@ extern int rtas_set_rtc_time(struct rtc_time *rtc_time);
 extern unsigned int rtas_busy_delay_time(int status);
 extern unsigned int rtas_busy_delay(int status);
 
+extern int early_init_dt_scan_rtas(unsigned long node,
+               const char *uname, int depth, void *data);
+
 extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
 
 /* Error types logged.  */
index 4463148c659f9672b4b4cadf48d79a037a462dcc..dcde4410348d2da87c890c6cb9fe8a2f30dcb69f 100644 (file)
@@ -18,8 +18,9 @@
 #include <linux/percpu.h>
 
 #include <asm/processor.h>
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_ISERIES
 #include <asm/paca.h>
+#include <asm/firmware.h>
 #include <asm/iseries/hv_call.h>
 #endif
 
@@ -177,7 +178,8 @@ static inline void set_dec(int val)
 #ifdef CONFIG_PPC_ISERIES
        int cur_dec;
 
-       if (get_lppaca()->shared_proc) {
+       if (firmware_has_feature(FW_FEATURE_ISERIES) &&
+                       get_lppaca()->shared_proc) {
                get_lppaca()->virtual_decr = val;
                cur_dec = get_dec();
                if (cur_dec > val)
diff --git a/include/asm-powerpc/todc.h b/include/asm-powerpc/todc.h
new file mode 100644 (file)
index 0000000..60a8c39
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * Definitions for the M48Txx and mc146818 series of Time of day/Real Time
+ * Clock chips.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+/*
+ * Support for the M48T37/M48T59/.../mc146818 Real Time Clock chips.
+ * Purpose is to make one generic file that handles all of these chips instead
+ * of every platform implementing the same code over & over again.
+ */
+
+#ifndef __PPC_KERNEL_TODC_H
+#define __PPC_KERNEL_TODC_H
+
+typedef struct {
+       uint rtc_type;          /* your particular chip */
+
+       /*
+        * Following are the addresses of the AS0, AS1, and DATA registers
+        * of these chips.  Note that these are board-specific.
+        */
+       unsigned int nvram_as0;
+       unsigned int nvram_as1;
+       unsigned int nvram_data;
+
+       /*
+        * Define bits to stop external set of regs from changing so
+        * the chip can be read/written reliably.
+        */
+       unsigned char enable_read;
+       unsigned char enable_write;
+
+       /*
+        * Following is the number of AS0 address bits.  This is normally
+        * 8 but some bad hardware routes address lines incorrectly.
+        */
+       int as0_bits;
+
+       int nvram_size; /* Size of NVRAM on chip */
+       int sw_flags;   /* Software control flags */
+
+       /* Following are the register offsets for the particular chip */
+       int year;
+       int month;
+       int day_of_month;
+       int day_of_week;
+       int hours;
+       int minutes;
+       int seconds;
+       int control_b;
+       int control_a;
+       int watchdog;
+       int interrupts;
+       int alarm_date;
+       int alarm_hour;
+       int alarm_minutes;
+       int alarm_seconds;
+       int century;
+       int flags;
+
+       /*
+        * Some RTC chips have their NVRAM buried behind a addr/data pair of
+        * regs on the first level/clock registers.  The following fields
+        * are the addresses for those addr/data regs.
+        */
+       int nvram_addr_reg;
+       int nvram_data_reg;
+} todc_info_t;
+
+/*
+ * Define the types of TODC/RTC variants that are supported in
+ * arch/ppc/kernel/todc_time.c
+ * Make a new one of these for any chip somehow differs from what's already
+ * defined.  That way, if you ever need to put in code to touch those
+ * bits/registers in todc_time.c, you can put it inside an
+ * 'if (todc_info->rtc_type == TODC_TYPE_XXX)' so you won't break
+ * anyone else.
+ */
+#define TODC_TYPE_MK48T35              1
+#define TODC_TYPE_MK48T37              2
+#define TODC_TYPE_MK48T59              3
+#define TODC_TYPE_DS1693               4       /* Dallas DS1693 RTC */
+#define TODC_TYPE_DS1743               5       /* Dallas DS1743 RTC */
+#define TODC_TYPE_DS1746               6       /* Dallas DS1746 RTC */
+#define TODC_TYPE_DS1747               7       /* Dallas DS1747 RTC */
+#define TODC_TYPE_DS1501               8       /* Dallas DS1501 RTC */
+#define TODC_TYPE_DS1643               9       /* Dallas DS1643 RTC */
+#define TODC_TYPE_PC97307              10      /* PC97307 internal RTC */
+#define TODC_TYPE_DS1557               11      /* Dallas DS1557 RTC */
+#define TODC_TYPE_DS17285              12      /* Dallas DS17285 RTC */
+#define TODC_TYPE_DS1553               13      /* Dallas DS1553 RTC */
+#define TODC_TYPE_MC146818             100     /* Leave room for m48txx's */
+
+/*
+ * Bit to clear/set to enable reads/writes to the chip
+ */
+#define TODC_MK48TXX_CNTL_A_R          0x40
+#define TODC_MK48TXX_CNTL_A_W          0x80
+#define TODC_MK48TXX_DAY_CB            0x80
+
+#define TODC_DS1501_CNTL_B_TE          0x80
+
+/*
+ * Define flag bits used by todc routines.
+ */
+#define TODC_FLAG_2_LEVEL_NVRAM                0x00000001
+
+/*
+ * Define the values for the various RTC's that should to into the todc_info
+ * table.
+ * Note: The XXX_NVRAM_SIZE, XXX_NVRAM_ADDR_REG, and XXX_NVRAM_DATA_REG only
+ * matter if XXX_SW_FLAGS has TODC_FLAG_2_LEVEL_NVRAM set.
+ */
+#define TODC_TYPE_MK48T35_NVRAM_SIZE           0x7ff8
+#define TODC_TYPE_MK48T35_SW_FLAGS             0
+#define TODC_TYPE_MK48T35_YEAR                 0x7fff
+#define TODC_TYPE_MK48T35_MONTH                        0x7ffe
+#define TODC_TYPE_MK48T35_DOM                  0x7ffd  /* Day of Month */
+#define TODC_TYPE_MK48T35_DOW                  0x7ffc  /* Day of Week */
+#define TODC_TYPE_MK48T35_HOURS                        0x7ffb
+#define TODC_TYPE_MK48T35_MINUTES              0x7ffa
+#define TODC_TYPE_MK48T35_SECONDS              0x7ff9
+#define TODC_TYPE_MK48T35_CNTL_B               0x7ff9
+#define TODC_TYPE_MK48T35_CNTL_A               0x7ff8
+#define TODC_TYPE_MK48T35_WATCHDOG             0x0000
+#define TODC_TYPE_MK48T35_INTERRUPTS           0x0000
+#define TODC_TYPE_MK48T35_ALARM_DATE           0x0000
+#define TODC_TYPE_MK48T35_ALARM_HOUR           0x0000
+#define TODC_TYPE_MK48T35_ALARM_MINUTES                0x0000
+#define TODC_TYPE_MK48T35_ALARM_SECONDS                0x0000
+#define TODC_TYPE_MK48T35_CENTURY              0x0000
+#define TODC_TYPE_MK48T35_FLAGS                        0x0000
+#define TODC_TYPE_MK48T35_NVRAM_ADDR_REG       0
+#define TODC_TYPE_MK48T35_NVRAM_DATA_REG       0
+
+#define TODC_TYPE_MK48T37_NVRAM_SIZE           0x7ff0
+#define TODC_TYPE_MK48T37_SW_FLAGS             0
+#define TODC_TYPE_MK48T37_YEAR                 0x7fff
+#define TODC_TYPE_MK48T37_MONTH                        0x7ffe
+#define TODC_TYPE_MK48T37_DOM                  0x7ffd  /* Day of Month */
+#define TODC_TYPE_MK48T37_DOW                  0x7ffc  /* Day of Week */
+#define TODC_TYPE_MK48T37_HOURS                        0x7ffb
+#define TODC_TYPE_MK48T37_MINUTES              0x7ffa
+#define TODC_TYPE_MK48T37_SECONDS              0x7ff9
+#define TODC_TYPE_MK48T37_CNTL_B               0x7ff9
+#define TODC_TYPE_MK48T37_CNTL_A               0x7ff8
+#define TODC_TYPE_MK48T37_WATCHDOG             0x7ff7
+#define TODC_TYPE_MK48T37_INTERRUPTS           0x7ff6
+#define TODC_TYPE_MK48T37_ALARM_DATE           0x7ff5
+#define TODC_TYPE_MK48T37_ALARM_HOUR           0x7ff4
+#define TODC_TYPE_MK48T37_ALARM_MINUTES                0x7ff3
+#define TODC_TYPE_MK48T37_ALARM_SECONDS                0x7ff2
+#define TODC_TYPE_MK48T37_CENTURY              0x7ff1
+#define TODC_TYPE_MK48T37_FLAGS                        0x7ff0
+#define TODC_TYPE_MK48T37_NVRAM_ADDR_REG       0
+#define TODC_TYPE_MK48T37_NVRAM_DATA_REG       0
+
+#define TODC_TYPE_MK48T59_NVRAM_SIZE           0x1ff0
+#define TODC_TYPE_MK48T59_SW_FLAGS             0
+#define TODC_TYPE_MK48T59_YEAR                 0x1fff
+#define TODC_TYPE_MK48T59_MONTH                        0x1ffe
+#define TODC_TYPE_MK48T59_DOM                  0x1ffd  /* Day of Month */
+#define TODC_TYPE_MK48T59_DOW                  0x1ffc  /* Day of Week */
+#define TODC_TYPE_MK48T59_HOURS                        0x1ffb
+#define TODC_TYPE_MK48T59_MINUTES              0x1ffa
+#define TODC_TYPE_MK48T59_SECONDS              0x1ff9
+#define TODC_TYPE_MK48T59_CNTL_B               0x1ff9
+#define TODC_TYPE_MK48T59_CNTL_A               0x1ff8
+#define TODC_TYPE_MK48T59_WATCHDOG             0x1fff
+#define TODC_TYPE_MK48T59_INTERRUPTS           0x1fff
+#define TODC_TYPE_MK48T59_ALARM_DATE           0x1fff
+#define TODC_TYPE_MK48T59_ALARM_HOUR           0x1fff
+#define TODC_TYPE_MK48T59_ALARM_MINUTES                0x1fff
+#define TODC_TYPE_MK48T59_ALARM_SECONDS                0x1fff
+#define TODC_TYPE_MK48T59_CENTURY              0x1fff
+#define TODC_TYPE_MK48T59_FLAGS                        0x1fff
+#define TODC_TYPE_MK48T59_NVRAM_ADDR_REG       0
+#define TODC_TYPE_MK48T59_NVRAM_DATA_REG       0
+
+#define TODC_TYPE_DS1501_NVRAM_SIZE    0x100
+#define TODC_TYPE_DS1501_SW_FLAGS      TODC_FLAG_2_LEVEL_NVRAM
+#define TODC_TYPE_DS1501_YEAR          (TODC_TYPE_DS1501_NVRAM_SIZE + 0x06)
+#define TODC_TYPE_DS1501_MONTH         (TODC_TYPE_DS1501_NVRAM_SIZE + 0x05)
+#define TODC_TYPE_DS1501_DOM           (TODC_TYPE_DS1501_NVRAM_SIZE + 0x04)
+#define TODC_TYPE_DS1501_DOW           (TODC_TYPE_DS1501_NVRAM_SIZE + 0x03)
+#define TODC_TYPE_DS1501_HOURS         (TODC_TYPE_DS1501_NVRAM_SIZE + 0x02)
+#define TODC_TYPE_DS1501_MINUTES       (TODC_TYPE_DS1501_NVRAM_SIZE + 0x01)
+#define TODC_TYPE_DS1501_SECONDS       (TODC_TYPE_DS1501_NVRAM_SIZE + 0x00)
+#define TODC_TYPE_DS1501_CNTL_B                (TODC_TYPE_DS1501_NVRAM_SIZE + 0x0f)
+#define TODC_TYPE_DS1501_CNTL_A                (TODC_TYPE_DS1501_NVRAM_SIZE + 0x0f)
+#define TODC_TYPE_DS1501_WATCHDOG      (TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define TODC_TYPE_DS1501_INTERRUPTS    (TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define TODC_TYPE_DS1501_ALARM_DATE    (TODC_TYPE_DS1501_NVRAM_SIZE + 0x0b)
+#define TODC_TYPE_DS1501_ALARM_HOUR    (TODC_TYPE_DS1501_NVRAM_SIZE + 0x0a)
+#define TODC_TYPE_DS1501_ALARM_MINUTES (TODC_TYPE_DS1501_NVRAM_SIZE + 0x09)
+#define TODC_TYPE_DS1501_ALARM_SECONDS (TODC_TYPE_DS1501_NVRAM_SIZE + 0x08)
+#define TODC_TYPE_DS1501_CENTURY       (TODC_TYPE_DS1501_NVRAM_SIZE + 0x07)
+#define TODC_TYPE_DS1501_FLAGS         (TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define TODC_TYPE_DS1501_NVRAM_ADDR_REG        0x10
+#define TODC_TYPE_DS1501_NVRAM_DATA_REG        0x13
+
+#define TODC_TYPE_DS1553_NVRAM_SIZE            0x1ff0
+#define TODC_TYPE_DS1553_SW_FLAGS              0
+#define TODC_TYPE_DS1553_YEAR                  0x1fff
+#define TODC_TYPE_DS1553_MONTH                 0x1ffe
+#define TODC_TYPE_DS1553_DOM                   0x1ffd  /* Day of Month */
+#define TODC_TYPE_DS1553_DOW                   0x1ffc  /* Day of Week */
+#define TODC_TYPE_DS1553_HOURS                 0x1ffb
+#define TODC_TYPE_DS1553_MINUTES               0x1ffa
+#define TODC_TYPE_DS1553_SECONDS               0x1ff9
+#define TODC_TYPE_DS1553_CNTL_B                        0x1ff9
+#define TODC_TYPE_DS1553_CNTL_A                        0x1ff8  /* control_a R/W regs */
+#define TODC_TYPE_DS1553_WATCHDOG              0x1ff7
+#define TODC_TYPE_DS1553_INTERRUPTS            0x1ff6
+#define TODC_TYPE_DS1553_ALARM_DATE            0x1ff5
+#define TODC_TYPE_DS1553_ALARM_HOUR            0x1ff4
+#define TODC_TYPE_DS1553_ALARM_MINUTES         0x1ff3
+#define TODC_TYPE_DS1553_ALARM_SECONDS         0x1ff2
+#define TODC_TYPE_DS1553_CENTURY               0x1ff8
+#define TODC_TYPE_DS1553_FLAGS                 0x1ff0
+#define TODC_TYPE_DS1553_NVRAM_ADDR_REG                0
+#define TODC_TYPE_DS1553_NVRAM_DATA_REG                0
+
+#define TODC_TYPE_DS1557_NVRAM_SIZE            0x7fff0
+#define TODC_TYPE_DS1557_SW_FLAGS              0
+#define TODC_TYPE_DS1557_YEAR                  0x7ffff
+#define TODC_TYPE_DS1557_MONTH                 0x7fffe
+#define TODC_TYPE_DS1557_DOM                   0x7fffd /* Day of Month */
+#define TODC_TYPE_DS1557_DOW                   0x7fffc /* Day of Week */
+#define TODC_TYPE_DS1557_HOURS                 0x7fffb
+#define TODC_TYPE_DS1557_MINUTES               0x7fffa
+#define TODC_TYPE_DS1557_SECONDS               0x7fff9
+#define TODC_TYPE_DS1557_CNTL_B                        0x7fff9
+#define TODC_TYPE_DS1557_CNTL_A                        0x7fff8 /* control_a R/W regs */
+#define TODC_TYPE_DS1557_WATCHDOG              0x7fff7
+#define TODC_TYPE_DS1557_INTERRUPTS            0x7fff6
+#define TODC_TYPE_DS1557_ALARM_DATE            0x7fff5
+#define TODC_TYPE_DS1557_ALARM_HOUR            0x7fff4
+#define TODC_TYPE_DS1557_ALARM_MINUTES         0x7fff3
+#define TODC_TYPE_DS1557_ALARM_SECONDS         0x7fff2
+#define TODC_TYPE_DS1557_CENTURY               0x7fff8
+#define TODC_TYPE_DS1557_FLAGS                 0x7fff0
+#define TODC_TYPE_DS1557_NVRAM_ADDR_REG                0
+#define TODC_TYPE_DS1557_NVRAM_DATA_REG                0
+
+#define TODC_TYPE_DS1643_NVRAM_SIZE            0x1ff8
+#define TODC_TYPE_DS1643_SW_FLAGS              0
+#define TODC_TYPE_DS1643_YEAR                  0x1fff
+#define TODC_TYPE_DS1643_MONTH                 0x1ffe
+#define TODC_TYPE_DS1643_DOM                   0x1ffd  /* Day of Month */
+#define TODC_TYPE_DS1643_DOW                   0x1ffc  /* Day of Week */
+#define TODC_TYPE_DS1643_HOURS                 0x1ffb
+#define TODC_TYPE_DS1643_MINUTES               0x1ffa
+#define TODC_TYPE_DS1643_SECONDS               0x1ff9
+#define TODC_TYPE_DS1643_CNTL_B                        0x1ff9
+#define TODC_TYPE_DS1643_CNTL_A                        0x1ff8  /* control_a R/W regs */
+#define TODC_TYPE_DS1643_WATCHDOG              0x1fff
+#define TODC_TYPE_DS1643_INTERRUPTS            0x1fff
+#define TODC_TYPE_DS1643_ALARM_DATE            0x1fff
+#define TODC_TYPE_DS1643_ALARM_HOUR            0x1fff
+#define TODC_TYPE_DS1643_ALARM_MINUTES         0x1fff
+#define TODC_TYPE_DS1643_ALARM_SECONDS         0x1fff
+#define TODC_TYPE_DS1643_CENTURY               0x1ff8
+#define TODC_TYPE_DS1643_FLAGS                 0x1fff
+#define TODC_TYPE_DS1643_NVRAM_ADDR_REG                0
+#define TODC_TYPE_DS1643_NVRAM_DATA_REG                0
+
+#define TODC_TYPE_DS1693_NVRAM_SIZE            0 /* Not handled yet */
+#define TODC_TYPE_DS1693_SW_FLAGS              0
+#define TODC_TYPE_DS1693_YEAR                  0x09
+#define TODC_TYPE_DS1693_MONTH                 0x08
+#define TODC_TYPE_DS1693_DOM                   0x07    /* Day of Month */
+#define TODC_TYPE_DS1693_DOW                   0x06    /* Day of Week */
+#define TODC_TYPE_DS1693_HOURS                 0x04
+#define TODC_TYPE_DS1693_MINUTES               0x02
+#define TODC_TYPE_DS1693_SECONDS               0x00
+#define TODC_TYPE_DS1693_CNTL_B                        0x0b
+#define TODC_TYPE_DS1693_CNTL_A                        0x0a
+#define TODC_TYPE_DS1693_WATCHDOG              0xff
+#define TODC_TYPE_DS1693_INTERRUPTS            0xff
+#define TODC_TYPE_DS1693_ALARM_DATE            0x49
+#define TODC_TYPE_DS1693_ALARM_HOUR            0x05
+#define TODC_TYPE_DS1693_ALARM_MINUTES         0x03
+#define TODC_TYPE_DS1693_ALARM_SECONDS         0x01
+#define TODC_TYPE_DS1693_CENTURY               0x48
+#define TODC_TYPE_DS1693_FLAGS                 0xff
+#define TODC_TYPE_DS1693_NVRAM_ADDR_REG                0
+#define TODC_TYPE_DS1693_NVRAM_DATA_REG                0
+
+#define TODC_TYPE_DS1743_NVRAM_SIZE            0x1ff8
+#define TODC_TYPE_DS1743_SW_FLAGS              0
+#define TODC_TYPE_DS1743_YEAR                  0x1fff
+#define TODC_TYPE_DS1743_MONTH                 0x1ffe
+#define TODC_TYPE_DS1743_DOM                   0x1ffd  /* Day of Month */
+#define TODC_TYPE_DS1743_DOW                   0x1ffc  /* Day of Week */
+#define TODC_TYPE_DS1743_HOURS                 0x1ffb
+#define TODC_TYPE_DS1743_MINUTES               0x1ffa
+#define TODC_TYPE_DS1743_SECONDS               0x1ff9
+#define TODC_TYPE_DS1743_CNTL_B                        0x1ff9
+#define TODC_TYPE_DS1743_CNTL_A                        0x1ff8  /* control_a R/W regs */
+#define TODC_TYPE_DS1743_WATCHDOG              0x1fff
+#define TODC_TYPE_DS1743_INTERRUPTS            0x1fff
+#define TODC_TYPE_DS1743_ALARM_DATE            0x1fff
+#define TODC_TYPE_DS1743_ALARM_HOUR            0x1fff
+#define TODC_TYPE_DS1743_ALARM_MINUTES         0x1fff
+#define TODC_TYPE_DS1743_ALARM_SECONDS         0x1fff
+#define TODC_TYPE_DS1743_CENTURY               0x1ff8
+#define TODC_TYPE_DS1743_FLAGS                 0x1fff
+#define TODC_TYPE_DS1743_NVRAM_ADDR_REG                0
+#define TODC_TYPE_DS1743_NVRAM_DATA_REG                0
+
+#define TODC_TYPE_DS1746_NVRAM_SIZE            0x1fff8
+#define TODC_TYPE_DS1746_SW_FLAGS              0
+#define TODC_TYPE_DS1746_YEAR                  0x1ffff
+#define TODC_TYPE_DS1746_MONTH                 0x1fffe
+#define TODC_TYPE_DS1746_DOM                   0x1fffd /* Day of Month */
+#define TODC_TYPE_DS1746_DOW                   0x1fffc /* Day of Week */
+#define TODC_TYPE_DS1746_HOURS                 0x1fffb
+#define TODC_TYPE_DS1746_MINUTES               0x1fffa
+#define TODC_TYPE_DS1746_SECONDS               0x1fff9
+#define TODC_TYPE_DS1746_CNTL_B                        0x1fff9
+#define TODC_TYPE_DS1746_CNTL_A                        0x1fff8 /* control_a R/W regs */
+#define TODC_TYPE_DS1746_WATCHDOG              0x00000
+#define TODC_TYPE_DS1746_INTERRUPTS            0x00000
+#define TODC_TYPE_DS1746_ALARM_DATE            0x00000
+#define TODC_TYPE_DS1746_ALARM_HOUR            0x00000
+#define TODC_TYPE_DS1746_ALARM_MINUTES         0x00000
+#define TODC_TYPE_DS1746_ALARM_SECONDS         0x00000
+#define TODC_TYPE_DS1746_CENTURY               0x00000
+#define TODC_TYPE_DS1746_FLAGS                 0x00000
+#define TODC_TYPE_DS1746_NVRAM_ADDR_REG                0
+#define TODC_TYPE_DS1746_NVRAM_DATA_REG                0
+
+#define TODC_TYPE_DS1747_NVRAM_SIZE            0x7fff8
+#define TODC_TYPE_DS1747_SW_FLAGS              0
+#define TODC_TYPE_DS1747_YEAR                  0x7ffff
+#define TODC_TYPE_DS1747_MONTH                 0x7fffe
+#define TODC_TYPE_DS1747_DOM                   0x7fffd /* Day of Month */
+#define TODC_TYPE_DS1747_DOW                   0x7fffc /* Day of Week */
+#define TODC_TYPE_DS1747_HOURS                 0x7fffb
+#define TODC_TYPE_DS1747_MINUTES               0x7fffa
+#define TODC_TYPE_DS1747_SECONDS               0x7fff9
+#define TODC_TYPE_DS1747_CNTL_B                        0x7fff9
+#define TODC_TYPE_DS1747_CNTL_A                        0x7fff8 /* control_a R/W regs */
+#define TODC_TYPE_DS1747_WATCHDOG              0x00000
+#define TODC_TYPE_DS1747_INTERRUPTS            0x00000
+#define TODC_TYPE_DS1747_ALARM_DATE            0x00000
+#define TODC_TYPE_DS1747_ALARM_HOUR            0x00000
+#define TODC_TYPE_DS1747_ALARM_MINUTES         0x00000
+#define TODC_TYPE_DS1747_ALARM_SECONDS         0x00000
+#define TODC_TYPE_DS1747_CENTURY               0x00000
+#define TODC_TYPE_DS1747_FLAGS                 0x00000
+#define TODC_TYPE_DS1747_NVRAM_ADDR_REG                0
+#define TODC_TYPE_DS1747_NVRAM_DATA_REG                0
+
+#define TODC_TYPE_DS17285_NVRAM_SIZE           (0x1000-0x80) /* 4Kx8 NVRAM (minus RTC regs) */
+#define TODC_TYPE_DS17285_SW_FLAGS             TODC_FLAG_2_LEVEL_NVRAM
+#define TODC_TYPE_DS17285_SECONDS              (TODC_TYPE_DS17285_NVRAM_SIZE + 0x00)
+#define TODC_TYPE_DS17285_ALARM_SECONDS                (TODC_TYPE_DS17285_NVRAM_SIZE + 0x01)
+#define TODC_TYPE_DS17285_MINUTES              (TODC_TYPE_DS17285_NVRAM_SIZE + 0x02)
+#define TODC_TYPE_DS17285_ALARM_MINUTES                (TODC_TYPE_DS17285_NVRAM_SIZE + 0x03)
+#define TODC_TYPE_DS17285_HOURS                        (TODC_TYPE_DS17285_NVRAM_SIZE + 0x04)
+#define TODC_TYPE_DS17285_ALARM_HOUR           (TODC_TYPE_DS17285_NVRAM_SIZE + 0x05)
+#define TODC_TYPE_DS17285_DOW                  (TODC_TYPE_DS17285_NVRAM_SIZE + 0x06)
+#define TODC_TYPE_DS17285_DOM                  (TODC_TYPE_DS17285_NVRAM_SIZE + 0x07)
+#define TODC_TYPE_DS17285_MONTH                        (TODC_TYPE_DS17285_NVRAM_SIZE + 0x08)
+#define TODC_TYPE_DS17285_YEAR                 (TODC_TYPE_DS17285_NVRAM_SIZE + 0x09)
+#define TODC_TYPE_DS17285_CNTL_A               (TODC_TYPE_DS17285_NVRAM_SIZE + 0x0A)
+#define TODC_TYPE_DS17285_CNTL_B               (TODC_TYPE_DS17285_NVRAM_SIZE + 0x0B)
+#define TODC_TYPE_DS17285_CNTL_C               (TODC_TYPE_DS17285_NVRAM_SIZE + 0x0C)
+#define TODC_TYPE_DS17285_CNTL_D               (TODC_TYPE_DS17285_NVRAM_SIZE + 0x0D)
+#define TODC_TYPE_DS17285_WATCHDOG             0
+#define TODC_TYPE_DS17285_INTERRUPTS           0
+#define TODC_TYPE_DS17285_ALARM_DATE           0
+#define TODC_TYPE_DS17285_CENTURY              0
+#define TODC_TYPE_DS17285_FLAGS                        0
+#define TODC_TYPE_DS17285_NVRAM_ADDR_REG       0x50
+#define TODC_TYPE_DS17285_NVRAM_DATA_REG       0x53
+
+#define TODC_TYPE_MC146818_NVRAM_SIZE          0       /* XXXX */
+#define TODC_TYPE_MC146818_SW_FLAGS            0
+#define TODC_TYPE_MC146818_YEAR                        0x09
+#define TODC_TYPE_MC146818_MONTH               0x08
+#define TODC_TYPE_MC146818_DOM                 0x07    /* Day of Month */
+#define TODC_TYPE_MC146818_DOW                 0x06    /* Day of Week */
+#define TODC_TYPE_MC146818_HOURS               0x04
+#define TODC_TYPE_MC146818_MINUTES             0x02
+#define TODC_TYPE_MC146818_SECONDS             0x00
+#define TODC_TYPE_MC146818_CNTL_B              0x0a
+#define TODC_TYPE_MC146818_CNTL_A              0x0b    /* control_a R/W regs */
+#define TODC_TYPE_MC146818_WATCHDOG            0
+#define TODC_TYPE_MC146818_INTERRUPTS          0x0c
+#define TODC_TYPE_MC146818_ALARM_DATE          0xff
+#define TODC_TYPE_MC146818_ALARM_HOUR          0x05
+#define TODC_TYPE_MC146818_ALARM_MINUTES       0x03
+#define TODC_TYPE_MC146818_ALARM_SECONDS       0x01
+#define TODC_TYPE_MC146818_CENTURY             0xff
+#define TODC_TYPE_MC146818_FLAGS               0xff
+#define TODC_TYPE_MC146818_NVRAM_ADDR_REG      0
+#define TODC_TYPE_MC146818_NVRAM_DATA_REG      0
+
+#define TODC_TYPE_PC97307_NVRAM_SIZE           0       /* No NVRAM? */
+#define TODC_TYPE_PC97307_SW_FLAGS             0
+#define TODC_TYPE_PC97307_YEAR                 0x09
+#define TODC_TYPE_PC97307_MONTH                        0x08
+#define TODC_TYPE_PC97307_DOM                  0x07    /* Day of Month */
+#define TODC_TYPE_PC97307_DOW                  0x06    /* Day of Week */
+#define TODC_TYPE_PC97307_HOURS                        0x04
+#define TODC_TYPE_PC97307_MINUTES              0x02
+#define TODC_TYPE_PC97307_SECONDS              0x00
+#define TODC_TYPE_PC97307_CNTL_B               0x0a
+#define TODC_TYPE_PC97307_CNTL_A               0x0b    /* control_a R/W regs */
+#define TODC_TYPE_PC97307_WATCHDOG             0x0c
+#define TODC_TYPE_PC97307_INTERRUPTS           0x0d
+#define TODC_TYPE_PC97307_ALARM_DATE           0xff
+#define TODC_TYPE_PC97307_ALARM_HOUR           0x05
+#define TODC_TYPE_PC97307_ALARM_MINUTES                0x03
+#define TODC_TYPE_PC97307_ALARM_SECONDS                0x01
+#define TODC_TYPE_PC97307_CENTURY              0xff
+#define TODC_TYPE_PC97307_FLAGS                        0xff
+#define TODC_TYPE_PC97307_NVRAM_ADDR_REG       0
+#define TODC_TYPE_PC97307_NVRAM_DATA_REG       0
+
+/*
+ * Define macros to allocate and init the todc_info_t table that will
+ * be used by the todc_time.c routines.
+ */
+#define TODC_ALLOC()                                                   \
+       static todc_info_t todc_info_alloc;                             \
+       todc_info_t *todc_info = &todc_info_alloc;
+
+#define TODC_INIT(clock_type, as0, as1, data, bits) {                  \
+       todc_info->rtc_type = clock_type;                               \
+                                                                       \
+       todc_info->nvram_as0 = (unsigned int)(as0);                     \
+       todc_info->nvram_as1 = (unsigned int)(as1);                     \
+       todc_info->nvram_data = (unsigned int)(data);                   \
+                                                                       \
+       todc_info->as0_bits = (bits);                                   \
+                                                                       \
+       todc_info->nvram_size = clock_type ##_NVRAM_SIZE;               \
+       todc_info->sw_flags = clock_type ##_SW_FLAGS;                   \
+                                                                       \
+       todc_info->year = clock_type ##_YEAR;                           \
+       todc_info->month = clock_type ##_MONTH;                         \
+       todc_info->day_of_month = clock_type ##_DOM;                    \
+       todc_info->day_of_week = clock_type ##_DOW;                     \
+       todc_info->hours = clock_type ##_HOURS;                         \
+       todc_info->minutes = clock_type ##_MINUTES;                     \
+       todc_info->seconds = clock_type ##_SECONDS;                     \
+       todc_info->control_b = clock_type ##_CNTL_B;                    \
+       todc_info->control_a = clock_type ##_CNTL_A;                    \
+       todc_info->watchdog = clock_type ##_WATCHDOG;                   \
+       todc_info->interrupts = clock_type ##_INTERRUPTS;               \
+       todc_info->alarm_date = clock_type ##_ALARM_DATE;               \
+       todc_info->alarm_hour = clock_type ##_ALARM_HOUR;               \
+       todc_info->alarm_minutes = clock_type ##_ALARM_MINUTES;         \
+       todc_info->alarm_seconds = clock_type ##_ALARM_SECONDS;         \
+       todc_info->century = clock_type ##_CENTURY;                     \
+       todc_info->flags = clock_type ##_FLAGS;                         \
+                                                                       \
+       todc_info->nvram_addr_reg = clock_type ##_NVRAM_ADDR_REG;       \
+       todc_info->nvram_data_reg = clock_type ##_NVRAM_DATA_REG;       \
+}
+
+extern todc_info_t *todc_info;
+
+unsigned char todc_direct_read_val(int addr);
+void todc_direct_write_val(int addr, unsigned char val);
+unsigned char todc_m48txx_read_val(int addr);
+void todc_m48txx_write_val(int addr, unsigned char val);
+unsigned char todc_mc146818_read_val(int addr);
+void todc_mc146818_write_val(int addr, unsigned char val);
+
+long todc_time_init(void);
+void todc_get_rtc_time(struct rtc_time *);
+int todc_set_rtc_time(struct rtc_time *);
+void todc_calibrate_decr(void);
+
+#endif                         /* __PPC_KERNEL_TODC_H */
index 92f3e5507d224cfc1cbf80e10d7d6bc09647a804..bbc3844b086fcadd9f529c69f5b12b6556530667 100644 (file)
@@ -93,5 +93,10 @@ static inline void sysfs_remove_device_from_node(struct sys_device *dev,
 
 #endif /* CONFIG_NUMA */
 
+#ifdef CONFIG_SMP
+#include <asm/cputable.h>
+#define smt_capable()          (cpu_has_feature(CPU_FTR_SMT))
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_TOPOLOGY_H */
diff --git a/include/asm-powerpc/tsi108.h b/include/asm-powerpc/tsi108.h
new file mode 100644 (file)
index 0000000..c4c278d
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * include/asm-ppc/tsi108.h
+ *
+ * common routine and memory layout for Tundra TSI108(Grendel) host bridge
+ * memory controller.
+ *
+ * Author: Jacob Pan (jacob.pan@freescale.com)
+ *        Alex Bounine (alexandreb@tundra.com)
+ * 2004 (c) Freescale Semiconductor Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef __PPC_KERNEL_TSI108_H
+#define __PPC_KERNEL_TSI108_H
+
+#include <asm/pci-bridge.h>
+
+/* Size of entire register space */
+#define TSI108_REG_SIZE                (0x10000)
+
+/* Sizes of register spaces for individual blocks */
+#define TSI108_HLP_SIZE                0x1000
+#define TSI108_PCI_SIZE                0x1000
+#define TSI108_CLK_SIZE                0x1000
+#define TSI108_PB_SIZE         0x1000
+#define TSI108_SD_SIZE         0x1000
+#define TSI108_DMA_SIZE                0x1000
+#define TSI108_ETH_SIZE                0x1000
+#define TSI108_I2C_SIZE                0x400
+#define TSI108_MPIC_SIZE       0x400
+#define TSI108_UART0_SIZE      0x200
+#define TSI108_GPIO_SIZE       0x200
+#define TSI108_UART1_SIZE      0x200
+
+/* Offsets within Tsi108(A) CSR space for individual blocks */
+#define TSI108_HLP_OFFSET      0x0000
+#define TSI108_PCI_OFFSET      0x1000
+#define TSI108_CLK_OFFSET      0x2000
+#define TSI108_PB_OFFSET       0x3000
+#define TSI108_SD_OFFSET       0x4000
+#define TSI108_DMA_OFFSET      0x5000
+#define TSI108_ETH_OFFSET      0x6000
+#define TSI108_I2C_OFFSET      0x7000
+#define TSI108_MPIC_OFFSET     0x7400
+#define TSI108_UART0_OFFSET    0x7800
+#define TSI108_GPIO_OFFSET     0x7A00
+#define TSI108_UART1_OFFSET    0x7C00
+
+/* Tsi108 registers used by common code components */
+#define TSI108_PCI_CSR         (0x004)
+#define TSI108_PCI_IRP_CFG_CTL (0x180)
+#define TSI108_PCI_IRP_STAT    (0x184)
+#define TSI108_PCI_IRP_ENABLE  (0x188)
+#define TSI108_PCI_IRP_INTAD   (0x18C)
+
+#define TSI108_PCI_IRP_STAT_P_INT      (0x00400000)
+#define TSI108_PCI_IRP_ENABLE_P_INT    (0x00400000)
+
+#define TSI108_CG_PWRUP_STATUS (0x234)
+
+#define TSI108_PB_ISR          (0x00C)
+#define TSI108_PB_ERRCS                (0x404)
+#define TSI108_PB_AERR         (0x408)
+
+#define TSI108_PB_ERRCS_ES             (1 << 1)
+#define TSI108_PB_ISR_PBS_RD_ERR       (1 << 8)
+
+#define TSI108_PCI_CFG_BASE_PHYS       (0xfb000000)
+#define TSI108_PCI_CFG_SIZE            (0x01000000)
+/* Global variables */
+
+extern u32 tsi108_pci_cfg_base;
+/* Exported functions */
+
+extern int tsi108_bridge_init(struct pci_controller *hose, uint phys_csr_base);
+extern unsigned long tsi108_get_mem_size(void);
+extern unsigned long tsi108_get_cpu_clk(void);
+extern unsigned long tsi108_get_sdc_clk(void);
+extern int tsi108_direct_write_config(struct pci_bus *bus, unsigned int devfn,
+                                     int offset, int len, u32 val);
+extern int tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn,
+                                    int offset, int len, u32 * val);
+extern void tsi108_clear_pci_error(u32 pci_cfg_base);
+
+extern phys_addr_t get_csrbase(void);
+
+typedef struct {
+       u32 regs;               /* hw registers base address */
+       u32 phyregs;            /* phy registers base address */
+       u16 phy;                /* phy address */
+       u16 irq_num;            /* irq number */
+       u8 mac_addr[6];         /* phy mac address */
+} hw_info;
+
+extern u32 get_vir_csrbase(void);
+extern u32 tsi108_csr_vir_base;
+
+extern inline u32 tsi108_read_reg(u32 reg_offset)
+{
+       return in_be32((volatile u32 *)(tsi108_csr_vir_base + reg_offset));
+}
+
+extern inline void tsi108_write_reg(u32 reg_offset, u32 val)
+{
+       out_be32((volatile u32 *)(tsi108_csr_vir_base + reg_offset), val);
+}
+
+#endif                         /* __PPC_KERNEL_TSI108_H */
index 19a1517ac43b7266f1fad7034863dd0fb8594bf9..55e57844fa789422f88858505f669a549809987f 100644 (file)
@@ -42,7 +42,8 @@ extern void __init udbg_init_debug_lpar(void);
 extern void __init udbg_init_pmac_realmode(void);
 extern void __init udbg_init_maple_realmode(void);
 extern void __init udbg_init_iseries(void);
-extern void __init udbg_init_rtas(void);
+extern void __init udbg_init_rtas_panel(void);
+extern void __init udbg_init_rtas_console(void);
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_UDBG_H */
index 3be5d760ffcd9c5eaa1a81ce0b6449cf2f68bfa7..16dbc7d174506e2b2754210ab24e7451f3cca6e7 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/device.h>
 
 #include <asm/mmu.h>
index 61434edbad7b7fd8489ca0a11743f0e604b565da..11ffaaa5da165abe9adec4d586eba35864fa71dc 100644 (file)
@@ -133,7 +133,7 @@ extern pgprot_t     pci_phys_mem_access_prot(struct file *file,
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
 extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
                                 const struct resource *rsrc,
-                                u64 *start, u64 *end);
+                                resource_size_t *start, resource_size_t *end);
 
 
 #endif /* __KERNEL__ */
index 4d2b126ba15961a6b7f7ee8b83d0e751d02b9a8c..0ddcdba79e4a91b6b04b140810994f31bd5636a8 100644 (file)
@@ -12,6 +12,9 @@
  *    Copyright (C) 1992, Linus Torvalds
  *
  */
+
+#ifdef __KERNEL__
+
 #include <linux/compiler.h>
 
 /*
  * with operation of the form "set_bit(bitnr, flags)".
  */
 
-/* set ALIGN_CS to 1 if the SMP safe bit operations should
- * align the address to 4 byte boundary. It seems to work
- * without the alignment. 
- */
-#ifdef __KERNEL__
-#define ALIGN_CS 0
-#else
-#define ALIGN_CS 1
-#ifndef CONFIG_SMP
-#error "bitops won't work without CONFIG_SMP"
-#endif
-#endif
-
 /* bitmap tables from arch/S390/kernel/bitmap.S */
 extern const char _oi_bitmap[];
 extern const char _ni_bitmap[];
@@ -121,10 +111,6 @@ static inline void set_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make OR mask */
@@ -141,10 +127,6 @@ static inline void clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make AND mask */
@@ -161,10 +143,6 @@ static inline void change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make XOR mask */
@@ -182,10 +160,6 @@ test_and_set_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make OR/test mask */
@@ -205,10 +179,6 @@ test_and_clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;    /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;         /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make AND/test mask */
@@ -228,10 +198,6 @@ test_and_change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
         unsigned long addr, old, new, mask;
 
        addr = (unsigned long) ptr;
-#if ALIGN_CS == 1
-       nr += (addr & __BITOPS_ALIGN) << 3;  /* add alignment to bit number */
-       addr ^= addr & __BITOPS_ALIGN;       /* align address to 8 */
-#endif
        /* calculate address for CS */
        addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
        /* make XOR/test mask */
@@ -834,8 +800,6 @@ static inline int sched_find_first_bit(unsigned long *b)
 
 #include <asm-generic/bitops/hweight.h>
 
-#ifdef __KERNEL__
-
 /*
  * ATTENTION: intel byte ordering convention for ext2 and minix !!
  * bit 0 is the LSB of addr; bit 31 is the MSB of addr;
index 089cf567c317b48f09501a377e73b320a59192d0..2b16193063513003e49e7327e8e5add0690f48a9 100644 (file)
@@ -276,6 +276,8 @@ extern void wait_cons_dev(void);
 
 extern void clear_all_subchannels(void);
 
+extern void css_schedule_reprobe(void);
+
 #endif
 
 #endif
index 2d09950a9c11207d43daaa593860256bc52438b1..241756f80df35260a06641d523f42a519170f513 100644 (file)
@@ -44,10 +44,6 @@ struct cmbdata {
 #define BIODASDCMFENABLE       _IO(DASD_IOCTL_LETTER,32)
 /* enable channel measurement */
 #define BIODASDCMFDISABLE      _IO(DASD_IOCTL_LETTER,33)
-/* reset channel measurement block */
-#define BIODASDRESETCMB                _IO(DASD_IOCTL_LETTER,34)
-/* read channel measurement data */
-#define BIODASDREADCMB         _IOWR(DASD_IOCTL_LETTER,32,__u64)
 /* read channel measurement data */
 #define BIODASDREADALLCMB      _IOWR(DASD_IOCTL_LETTER,33,struct cmbdata)
 
index 1630c26e8f45a5c27eef949454fb4702747fc7f0..c042f9578081a4ece5e06afb1b996bd558ed3416 100644 (file)
@@ -68,10 +68,12 @@ typedef struct dasd_information2_t {
  * 0x00: default features
  * 0x01: readonly (ro)
  * 0x02: use diag discipline (diag)
+ * 0x04: set the device initially online (internal use only)
  */
-#define DASD_FEATURE_DEFAULT  0
-#define DASD_FEATURE_READONLY 1
-#define DASD_FEATURE_USEDIAG  2
+#define DASD_FEATURE_DEFAULT        0x00
+#define DASD_FEATURE_READONLY       0x01
+#define DASD_FEATURE_USEDIAG        0x02
+#define DASD_FEATURE_INITIAL_ONLINE  0x04
 
 #define DASD_PARTN_BITS 2
 
index 8e0c7ed73d0312a811c5a3f887527747a6c669c3..0a518915bf90f1087466444caf0809a8b9b3a02b 100644 (file)
@@ -63,6 +63,7 @@ struct thread_info {
        .exec_domain    = &default_exec_domain, \
        .flags          = 0,                    \
        .cpu            = 0,                    \
+       .preempt_count  = 1,                    \
        .restart_block  = {                     \
                .fn = do_no_restart_syscall,    \
        },                                      \
index e21443d3ea1df4532562d613571f611c1b464a63..aa7a243862e1b714afbc0803de501b1ab2b13e69 100644 (file)
 
 #ifdef __KERNEL__
 
-/* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
-
 #define __syscall_return(type, res)                         \
 do {                                                        \
-       if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+       if ((unsigned long)(res) >= (unsigned long)(-4095)) {\
                errno = -(res);                              \
                res = -1;                                    \
        }                                                    \
index 1d934fb2c581c69ac6b6fe7906af5adc010a2f01..fed26616967a03979d0d6ea6e7c14d1d6a446f97 100644 (file)
@@ -1,9 +1,4 @@
 #ifndef __ASM_SH_HW_IRQ_H
 #define __ASM_SH_HW_IRQ_H
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
-       /* Nothing to do */
-}
-
 #endif /* __ASM_SH_HW_IRQ_H */
index ae718d1f2d6cc90d416284453c5c01cdbfb652dd..ebb39089b0acf3be7f39841243447e3b94427a07 100644 (file)
@@ -11,6 +11,5 @@
  * Copyright (C) 2000, 2001  Paolo Alberelli
  *
  */
-static __inline__ void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { /* Nothing to do */ }
 
 #endif /* __ASM_SH64_HW_IRQ_H */
index 0e234e201bd6b587375e17cdb450daae6c47b22c..98a6c613589dcbe29205d0705ebf871b6f577b22 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef _ASM_SPARC64_TOPOLOGY_H
 #define _ASM_SPARC64_TOPOLOGY_H
 
+#include <asm/spitfire.h>
+#define smt_capable()  (tlb_type == hypervisor)
+
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_SPARC64_TOPOLOGY_H */
index 4ee38c0b6a64c0378c110cf7beb9d2aeeebfeae6..1cf84cf5f21af301596b5439289e1183071e2661 100644 (file)
@@ -4,7 +4,4 @@
 #include "asm/irq.h"
 #include "asm/archparam.h"
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{}
-
 #endif
index a8aab4342712a77a7e1f2ac49ae8b536fb270d40..043e94bb6bd8e51f0c94dd6473c92d00e4f86a99 100644 (file)
@@ -1,8 +1,4 @@
 #ifndef __V850_HW_IRQ_H__
 #define __V850_HW_IRQ_H__
 
-static inline void hw_resend_irq (struct hw_interrupt_type *h, unsigned int i)
-{
-}
-
 #endif /* __V850_HW_IRQ_H__ */
index 1b2ac55d3204e9ed6bbf3816fd82c50fa774f461..48a4a5364e85ddfc651c6716e0cf54deeac21df2 100644 (file)
@@ -124,18 +124,9 @@ asmlinkage void IRQ_NAME(nr); \
 __asm__( \
 "\n.p2align\n" \
 "IRQ" #nr "_interrupt:\n\t" \
-       "push $" #nr "-256 ; " \
+       "push $~(" #nr ") ; " \
        "jmp common_interrupt");
 
-#if defined(CONFIG_X86_IO_APIC)
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
-       if (IO_APIC_IRQ(i))
-               send_IPI_self(IO_APIC_VECTOR(i));
-}
-#else
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
-#endif
-
 #define platform_legacy_irq(irq)       ((irq) < 16)
 
 #endif
index c4e46e7fa7ba781f9c086bf2ace317d105d9ba56..6e7a2e976b04fc8bc8a98213522fabf5c623af02 100644 (file)
@@ -59,6 +59,8 @@ extern int __node_distance(int, int);
 #define topology_core_id(cpu)                  (cpu_data[cpu].cpu_core_id)
 #define topology_core_siblings(cpu)            (cpu_core_map[cpu])
 #define topology_thread_siblings(cpu)          (cpu_sibling_map[cpu])
+#define mc_capable()                   (boot_cpu_data.x86_max_cores > 1)
+#define smt_capable()                  (smp_num_siblings > 1)
 #endif
 
 #include <asm-generic/topology.h>
index ccf436249eaaa90f66c6d746701bcce74f1f01ad..3ddbea759b2bc32be0839976e1d582b23f90fdfe 100644 (file)
@@ -11,8 +11,4 @@
 #ifndef _XTENSA_HW_IRQ_H
 #define _XTENSA_HW_IRQ_H
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
-{
-}
-
 #endif
index c35833824e118d8f9012542647f4f96ba95fb3d7..2ed2fd855133cba6d445a4babdb213e4eb4b2f75 100644 (file)
@@ -259,7 +259,7 @@ struct ac97_codec {
        int type;
        u32 model;
 
-       int modem:1;
+       unsigned int modem:1;
 
        struct ac97_ops *codec_ops;
 
index 90d6df1551ed06964d6f326866790531e7c04780..88b5dfd8ee125be2c3a025c7ea1e03183eaccbe4 100644 (file)
@@ -528,12 +528,18 @@ static inline void acpi_set_cstate_limit(unsigned int new_limit) { return; }
 
 #ifdef CONFIG_ACPI_NUMA
 int acpi_get_pxm(acpi_handle handle);
+int acpi_get_node(acpi_handle *handle);
 #else
 static inline int acpi_get_pxm(acpi_handle handle)
 {
        return 0;
 }
+static inline int acpi_get_node(acpi_handle *handle)
+{
+       return 0;
+}
 #endif
+extern int acpi_paddr_to_node(u64 start_addr, u64 size);
 
 extern int pnpacpi_disabled;
 
index fb7e9b7ccbe312bf29ecada865da27dc152fb51d..737e407d0cd11e7479e6d38d3cf48562eec4f596 100644 (file)
@@ -149,7 +149,6 @@ void create_empty_buffers(struct page *, unsigned long,
                        unsigned long b_state);
 void end_buffer_read_sync(struct buffer_head *bh, int uptodate);
 void end_buffer_write_sync(struct buffer_head *bh, int uptodate);
-void end_buffer_async_write(struct buffer_head *bh, int uptodate);
 
 /* Things to do with buffers at mapping->private_list */
 void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode);
@@ -214,6 +213,7 @@ int nobh_truncate_page(struct address_space *, loff_t);
 int nobh_writepage(struct page *page, get_block_t *get_block,
                         struct writeback_control *wbc);
 
+void buffer_init(void);
 
 /*
  * inline definitions
index 7b5c5df5cb69213ab7c2b5e45f1939c2b2ddc8b5..be512cc98791a31b85c0317e6f2b19e1e90c3631 100644 (file)
@@ -27,8 +27,8 @@ extern struct inode_operations coda_dir_inode_operations;
 extern struct inode_operations coda_file_inode_operations;
 extern struct inode_operations coda_ioctl_inode_operations;
 
-extern struct address_space_operations coda_file_aops;
-extern struct address_space_operations coda_symlink_aops;
+extern const struct address_space_operations coda_file_aops;
+extern const struct address_space_operations coda_symlink_aops;
 
 extern const struct file_operations coda_dir_operations;
 extern const struct file_operations coda_file_operations;
index 917d62e4148073ebb80d82cec1bb7399da468e1d..269d000bb2a3e6f283a66a177b779069acc4962f 100644 (file)
@@ -567,11 +567,6 @@ COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
 COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
 COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
-/* DEVFS */
-COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
-COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
-COMPATIBLE_IOCTL(DEVFSDIOC_RELEASE_EVENT_QUEUE)
-COMPATIBLE_IOCTL(DEVFSDIOC_SET_DEBUG_MASK)
 /* Raw devices */
 COMPATIBLE_IOCTL(RAW_SETBIND)
 COMPATIBLE_IOCTL(RAW_GETBIND)
index 08d50c53aab401ef79c20e85213027d854e5d199..a3caf6866bae588885c43618d9965a6285f0913c 100644 (file)
@@ -31,17 +31,23 @@ struct cpu {
        struct sys_device sysdev;
 };
 
-extern int register_cpu(struct cpu *, int, struct node *);
+extern int register_cpu(struct cpu *cpu, int num);
 extern struct sys_device *get_cpu_sysdev(unsigned cpu);
 #ifdef CONFIG_HOTPLUG_CPU
-extern void unregister_cpu(struct cpu *, struct node *);
+extern void unregister_cpu(struct cpu *cpu);
 #endif
 struct notifier_block;
 
 #ifdef CONFIG_SMP
 /* Need to know about CPUs going up/down? */
 extern int register_cpu_notifier(struct notifier_block *nb);
+#ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu_notifier(struct notifier_block *nb);
+#else
+static inline void unregister_cpu_notifier(struct notifier_block *nb)
+{
+}
+#endif
 extern int current_in_cpu_hotplug(void);
 
 int cpu_up(unsigned int cpu);
@@ -73,6 +79,8 @@ extern int lock_cpu_hotplug_interruptible(void);
                { .notifier_call = fn, .priority = pri };       \
        register_cpu_notifier(&fn##_nb);                        \
 }
+#define register_hotcpu_notifier(nb)   register_cpu_notifier(nb)
+#define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb)
 int cpu_down(unsigned int cpu);
 #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
 #else
@@ -80,6 +88,8 @@ int cpu_down(unsigned int cpu);
 #define unlock_cpu_hotplug()   do { } while (0)
 #define lock_cpu_hotplug_interruptible() 0
 #define hotcpu_notifier(fn, pri)
+#define register_hotcpu_notifier(nb)
+#define unregister_hotcpu_notifier(nb)
 
 /* CPUs don't go offline once they're online w/o CONFIG_HOTPLUG_CPU */
 static inline int cpu_is_offline(int cpu) { return 0; }
diff --git a/include/linux/devfs_fs.h b/include/linux/devfs_fs.h
deleted file mode 100644 (file)
index de236f4..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef _LINUX_DEVFS_FS_H
-#define _LINUX_DEVFS_FS_H
-
-#include <linux/ioctl.h>
-
-#define DEVFSD_PROTOCOL_REVISION_KERNEL  5
-
-#define        DEVFSD_IOCTL_BASE       'd'
-
-/*  These are the various ioctls  */
-#define DEVFSDIOC_GET_PROTO_REV         _IOR(DEVFSD_IOCTL_BASE, 0, int)
-#define DEVFSDIOC_SET_EVENT_MASK        _IOW(DEVFSD_IOCTL_BASE, 2, int)
-#define DEVFSDIOC_RELEASE_EVENT_QUEUE   _IOW(DEVFSD_IOCTL_BASE, 3, int)
-#define DEVFSDIOC_SET_DEBUG_MASK        _IOW(DEVFSD_IOCTL_BASE, 4, int)
-
-#define DEVFSD_NOTIFY_REGISTERED    0
-#define DEVFSD_NOTIFY_UNREGISTERED  1
-#define DEVFSD_NOTIFY_ASYNC_OPEN    2
-#define DEVFSD_NOTIFY_CLOSE         3
-#define DEVFSD_NOTIFY_LOOKUP        4
-#define DEVFSD_NOTIFY_CHANGE        5
-#define DEVFSD_NOTIFY_CREATE        6
-#define DEVFSD_NOTIFY_DELETE        7
-
-#define DEVFS_PATHLEN               1024       /*  Never change this otherwise the
-                                                  binary interface will change   */
-
-struct devfsd_notify_struct {  /*  Use native C types to ensure same types in kernel and user space     */
-       unsigned int type;      /*  DEVFSD_NOTIFY_* value                   */
-       unsigned int mode;      /*  Mode of the inode or device entry       */
-       unsigned int major;     /*  Major number of device entry            */
-       unsigned int minor;     /*  Minor number of device entry            */
-       unsigned int uid;       /*  Uid of process, inode or device entry   */
-       unsigned int gid;       /*  Gid of process, inode or device entry   */
-       unsigned int overrun_count;     /*  Number of lost events                   */
-       unsigned int namelen;   /*  Number of characters not including '\0' */
-       /*  The device name MUST come last                                       */
-       char devname[DEVFS_PATHLEN];    /*  This will be '\0' terminated            */
-};
-
-#endif                         /*  _LINUX_DEVFS_FS_H  */
diff --git a/include/linux/devfs_fs_kernel.h b/include/linux/devfs_fs_kernel.h
deleted file mode 100644 (file)
index 0d74a6f..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef _LINUX_DEVFS_FS_KERNEL_H
-#define _LINUX_DEVFS_FS_KERNEL_H
-
-#include <linux/fs.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <asm/semaphore.h>
-
-#define DEVFS_SUPER_MAGIC                0x1373
-
-#ifdef CONFIG_DEVFS_FS
-extern int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
-    __attribute__ ((format(printf, 3, 4)));
-extern int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...)
-    __attribute__ ((format(printf, 3, 4)));
-extern int devfs_mk_symlink(const char *name, const char *link);
-extern int devfs_mk_dir(const char *fmt, ...)
-    __attribute__ ((format(printf, 1, 2)));
-extern void devfs_remove(const char *fmt, ...)
-    __attribute__ ((format(printf, 1, 2)));
-extern int devfs_register_tape(const char *name);
-extern void devfs_unregister_tape(int num);
-extern void mount_devfs_fs(void);
-#else                          /*  CONFIG_DEVFS_FS  */
-static inline int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
-{
-       return 0;
-}
-static inline int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...)
-{
-       return 0;
-}
-static inline int devfs_mk_symlink(const char *name, const char *link)
-{
-       return 0;
-}
-static inline int devfs_mk_dir(const char *fmt, ...)
-{
-       return 0;
-}
-static inline void devfs_remove(const char *fmt, ...)
-{
-}
-static inline int devfs_register_tape(const char *name)
-{
-       return -1;
-}
-static inline void devfs_unregister_tape(int num)
-{
-}
-static inline void mount_devfs_fs(void)
-{
-       return;
-}
-#endif                         /*  CONFIG_DEVFS_FS  */
-#endif                         /*  _LINUX_DEVFS_FS_KERNEL_H  */
index 78b236ca04f801ec188f1f78306ee44d10e02d95..272010a6078a9181dfb4a49a51f3820d47ee1b01 100644 (file)
@@ -20,7 +20,7 @@
  */
 #ifndef DMAENGINE_H
 #define DMAENGINE_H
-#include <linux/config.h>
+
 #ifdef CONFIG_DMA_ENGINE
 
 #include <linux/device.h>
index fbfa6b52e2fb0007a3ec29b7a003fc3981981d19..278ef4495819509748a2e1b3c53651202bbcf1f9 100644 (file)
@@ -38,7 +38,7 @@ struct statfs;
 
 extern struct inode_operations efs_dir_inode_operations;
 extern const struct file_operations efs_dir_operations;
-extern struct address_space_operations efs_symlink_aops;
+extern const struct address_space_operations efs_symlink_aops;
 
 extern void efs_read_inode(struct inode *);
 extern efs_block_t efs_map_block(struct inode *, efs_block_t);
index 114a96d25652200ab797b35ed01eab2dabac1e05..6a5796c81c900c97ead2d871a6f612c398391afa 100644 (file)
 #define EM_486         6       /* Perhaps disused */
 #define EM_860         7
 #define EM_MIPS                8       /* MIPS R3000 (officially, big-endian only) */
+                               /* Next two are historical and binaries and
+                                  modules of these types will be rejected by
+                                  Linux.  */
+#define EM_MIPS_RS3_LE 10      /* MIPS R3000 little-endian */
 #define EM_MIPS_RS4_BE 10      /* MIPS R4000 big-endian */
+
 #define EM_PARISC      15      /* HPPA */
 #define EM_SPARC32PLUS 18      /* Sun's "v8plus" */
 #define EM_PPC         20      /* PowerPC */
index 07a08e92bc736889b9c3077a2b379353fb500f7a..b45928f5c63fe838dee88eb7d03da5a6e4679e8b 100644 (file)
@@ -380,7 +380,6 @@ struct fb_cursor {
 #include <linux/tty.h>
 #include <linux/device.h>
 #include <linux/workqueue.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/notifier.h>
 #include <linux/list.h>
 #include <asm/io.h>
index 2d8b348c11923ad57d803982040c3563bf612e52..e04a5cfe874f978c91efbaa3bfe5ac71d259aefe 100644 (file)
@@ -392,7 +392,7 @@ struct address_space {
        unsigned int            truncate_count; /* Cover race condition with truncate */
        unsigned long           nrpages;        /* number of total pages */
        pgoff_t                 writeback_index;/* writeback starts here */
-       struct address_space_operations *a_ops; /* methods */
+       const struct address_space_operations *a_ops;   /* methods */
        unsigned long           flags;          /* error bits/gfp mask */
        struct backing_dev_info *backing_dev_info; /* device readahead, etc */
        spinlock_t              private_lock;   /* for use by the address_space */
@@ -1405,7 +1405,7 @@ extern void bd_forget(struct inode *inode);
 extern void bdput(struct block_device *);
 extern struct block_device *open_by_devnum(dev_t, unsigned);
 extern const struct file_operations def_blk_fops;
-extern struct address_space_operations def_blk_aops;
+extern const struct address_space_operations def_blk_aops;
 extern const struct file_operations def_chr_fops;
 extern const struct file_operations bad_sock_fops;
 extern const struct file_operations def_fifo_fops;
index 966a5b3da439b40232c269f44026733db5a76244..34c3a215f2cd9affe3583451063a09887ee0669c 100644 (file)
@@ -12,6 +12,9 @@
 #define FUTEX_REQUEUE          3
 #define FUTEX_CMP_REQUEUE      4
 #define FUTEX_WAKE_OP          5
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
 
 /*
  * Support for robust futexes: the kernel cleans up held futexes at
@@ -90,18 +93,21 @@ struct robust_list_head {
  */
 #define ROBUST_LIST_LIMIT      2048
 
-long do_futex(unsigned long uaddr, int op, int val,
-               unsigned long timeout, unsigned long uaddr2, int val2,
-               int val3);
+long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
+             u32 __user *uaddr2, u32 val2, u32 val3);
 
 extern int handle_futex_death(u32 __user *uaddr, struct task_struct *curr);
 
 #ifdef CONFIG_FUTEX
 extern void exit_robust_list(struct task_struct *curr);
+extern void exit_pi_state_list(struct task_struct *curr);
 #else
 static inline void exit_robust_list(struct task_struct *curr)
 {
 }
+static inline void exit_pi_state_list(struct task_struct *curr)
+{
+}
 #endif
 
 #define FUTEX_OP_SET           0       /* *(int *)UADDR2 = OPARG; */
index 3498a0c6818441cb9a81f6e329dac5fa8b03f7e3..e4af57e87c178ab0bff22b97b2e710e72a870428 100644 (file)
@@ -112,8 +112,6 @@ struct gendisk {
        sector_t capacity;
 
        int flags;
-       char devfs_name[64];            /* devfs crap */
-       int number;                     /* more of the same */
        struct device *driverfs_dev;
        struct kobject kobj;
        struct kobject *holder_dir;
index ef7bef207f48d3ae0b458c063e788eaf69f803d3..285316c836b5436932f9d90abb384d16ef983b59 100644 (file)
@@ -552,7 +552,6 @@ typedef struct ide_drive_s {
        struct hd_driveid       *id;    /* drive model identification info */
        struct proc_dir_entry *proc;    /* /proc/ide/ directory entry */
        struct ide_settings_s *settings;/* /proc/ide/ drive settings */
-       char            devfs_name[64]; /* devfs crap */
 
        struct hwif_s           *hwif;  /* actually (ide_hwif_t *) */
 
@@ -793,6 +792,7 @@ typedef struct hwif_s {
        unsigned        auto_poll  : 1; /* supports nop auto-poll */
        unsigned        sg_mapped  : 1; /* sg_table and sg_nents are ready */
        unsigned        no_io_32bit : 1; /* 1 = can not do 32-bit IO ops */
+       unsigned        err_stops_fifo : 1; /* 1=data FIFO is cleared by an error */
 
        struct device   gendev;
        struct completion gendev_rel_comp; /* To deal with device release() */
index e127ef7e8da834dd3300ab875349c530b8a5e60d..3a256957fb56a7f05453dd3ea60cb075ca086b01 100644 (file)
@@ -87,6 +87,7 @@ extern struct group_info init_groups;
        .lock_depth     = -1,                                           \
        .prio           = MAX_PRIO-20,                                  \
        .static_prio    = MAX_PRIO-20,                                  \
+       .normal_prio    = MAX_PRIO-20,                                  \
        .policy         = SCHED_NORMAL,                                 \
        .cpus_allowed   = CPU_MASK_ALL,                                 \
        .mm             = NULL,                                         \
@@ -122,6 +123,8 @@ extern struct group_info init_groups;
        .journal_info   = NULL,                                         \
        .cpu_timers     = INIT_CPU_TIMERS(tsk.cpu_timers),              \
        .fs_excl        = ATOMIC_INIT(0),                               \
+       .pi_lock        = SPIN_LOCK_UNLOCKED,                           \
+       INIT_RT_MUTEXES(tsk)                                            \
 }
 
 
index 70741e170114e5f9328553fa9b8eadc1a60fc7ab..db2a63a11633cb9ebdfeb21dc9436b1a23bd92ea 100644 (file)
@@ -36,6 +36,20 @@ extern void free_irq(unsigned int, void *);
 extern void disable_irq_nosync(unsigned int irq);
 extern void disable_irq(unsigned int irq);
 extern void enable_irq(unsigned int irq);
+
+/* IRQ wakeup (PM) control: */
+extern int set_irq_wake(unsigned int irq, unsigned int on);
+
+static inline int enable_irq_wake(unsigned int irq)
+{
+       return set_irq_wake(irq, 1);
+}
+
+static inline int disable_irq_wake(unsigned int irq)
+{
+       return set_irq_wake(irq, 0);
+}
+
 #endif
 
 #ifndef __ARCH_SET_SOFTIRQ_PENDING
index cd6bd001ba4edbc68dfc5b52f08ef3bb832c785e..87a9fc039b4789e6d68e65510cb06bafaf18c801 100644 (file)
@@ -9,13 +9,15 @@
 #define _LINUX_IOPORT_H
 
 #include <linux/compiler.h>
+#include <linux/types.h>
 /*
  * Resources are tree-like, allowing
  * nesting etc..
  */
 struct resource {
+       resource_size_t start;
+       resource_size_t end;
        const char *name;
-       unsigned long start, end;
        unsigned long flags;
        struct resource *parent, *sibling, *child;
 };
@@ -96,31 +98,37 @@ extern struct resource * ____request_resource(struct resource *root, struct reso
 extern int release_resource(struct resource *new);
 extern __deprecated_for_modules int insert_resource(struct resource *parent, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,
-                            unsigned long size,
-                            unsigned long min, unsigned long max,
-                            unsigned long align,
+                            resource_size_t size, resource_size_t min,
+                            resource_size_t max, resource_size_t align,
                             void (*alignf)(void *, struct resource *,
-                                           unsigned long, unsigned long),
+                                           resource_size_t, resource_size_t),
                             void *alignf_data);
-int adjust_resource(struct resource *res, unsigned long start,
-                   unsigned long size);
+int adjust_resource(struct resource *res, resource_size_t start,
+                   resource_size_t size);
+
+/* get registered SYSTEM_RAM resources in specified area */
+extern int find_next_system_ram(struct resource *res);
 
 /* Convenience shorthand with allocation */
 #define request_region(start,n,name)   __request_region(&ioport_resource, (start), (n), (name))
 #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))
 #define rename_region(region, newname) do { (region)->name = (newname); } while (0)
 
-extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name);
+extern struct resource * __request_region(struct resource *,
+                                       resource_size_t start,
+                                       resource_size_t n, const char *name);
 
 /* Compatibility cruft */
 #define release_region(start,n)        __release_region(&ioport_resource, (start), (n))
 #define check_mem_region(start,n)      __check_region(&iomem_resource, (start), (n))
 #define release_mem_region(start,n)    __release_region(&iomem_resource, (start), (n))
 
-extern int __check_region(struct resource *, unsigned long, unsigned long);
-extern void __release_region(struct resource *, unsigned long, unsigned long);
+extern int __check_region(struct resource *, resource_size_t, resource_size_t);
+extern void __release_region(struct resource *, resource_size_t,
+                               resource_size_t);
 
-static inline int __deprecated check_region(unsigned long s, unsigned long n)
+static inline int __deprecated check_region(resource_size_t s,
+                                               resource_size_t n)
 {
        return __check_region(&ioport_resource, s, n);
 }
index 5653b2f23b6a6fdf94f0e1d15ae8cb7436638db0..d09fbeabf1dc976539384f1889299bfc2e69383e 100644 (file)
@@ -210,11 +210,7 @@ struct kernel_ipmi_msg
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/device.h>
-
-#ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
-extern struct proc_dir_entry *proc_ipmi_root;
-#endif /* CONFIG_PROC_FS */
 
 /* Opaque type for a IPMI message user.  One of these is needed to
    send and receive messages. */
index 676e00dfb21a623c6922436646cc4e85be8d7656..0832149cdb180df6e8ba75e1f7a951c438b03546 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __irq_h
-#define __irq_h
+#ifndef _LINUX_IRQ_H
+#define _LINUX_IRQ_H
 
 /*
  * Please do not include this file in generic code.  There is currently
@@ -11,7 +11,7 @@
 
 #include <linux/smp.h>
 
-#if !defined(CONFIG_S390)
+#ifndef CONFIG_S390
 
 #include <linux/linkage.h>
 #include <linux/cache.h>
 #define IRQ_WAITING    32      /* IRQ not yet seen - for autodetection */
 #define IRQ_LEVEL      64      /* IRQ level triggered */
 #define IRQ_MASKED     128     /* IRQ masked - shouldn't be seen again */
-#if defined(ARCH_HAS_IRQ_PER_CPU)
+#ifdef CONFIG_IRQ_PER_CPU
 # define IRQ_PER_CPU   256     /* IRQ is per CPU */
 # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
 #else
 # define CHECK_IRQ_PER_CPU(var) 0
 #endif
 
+#define IRQ_NOPROBE    512     /* IRQ is not valid for probing */
+#define IRQ_NOREQUEST  1024    /* IRQ cannot be requested */
+#define IRQ_NOAUTOEN   2048    /* IRQ will not be enabled on request irq */
+#define IRQ_DELAYED_DISABLE \
+                       4096    /* IRQ disable (masking) happens delayed. */
+
 /*
- * Interrupt controller descriptor. This is all we need
- * to describe about the low-level hardware. 
+ * IRQ types, see also include/linux/interrupt.h
  */
-struct hw_interrupt_type {
-       const char * typename;
-       unsigned int (*startup)(unsigned int irq);
-       void (*shutdown)(unsigned int irq);
-       void (*enable)(unsigned int irq);
-       void (*disable)(unsigned int irq);
-       void (*ack)(unsigned int irq);
-       void (*end)(unsigned int irq);
-       void (*set_affinity)(unsigned int irq, cpumask_t dest);
+#define IRQ_TYPE_NONE          0x0000          /* Default, unspecified type */
+#define IRQ_TYPE_EDGE_RISING   0x0001          /* Edge rising type */
+#define IRQ_TYPE_EDGE_FALLING  0x0002          /* Edge falling type */
+#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
+#define IRQ_TYPE_LEVEL_HIGH    0x0004          /* Level high type */
+#define IRQ_TYPE_LEVEL_LOW     0x0008          /* Level low type */
+#define IRQ_TYPE_SENSE_MASK    0x000f          /* Mask of the above */
+#define IRQ_TYPE_SIMPLE                0x0010          /* Simple type */
+#define IRQ_TYPE_PERCPU                0x0020          /* Per CPU type */
+#define IRQ_TYPE_PROBE         0x0040          /* Probing in progress */
+
+struct proc_dir_entry;
+
+/**
+ * struct irq_chip - hardware interrupt chip descriptor
+ *
+ * @name:              name for /proc/interrupts
+ * @startup:           start up the interrupt (defaults to ->enable if NULL)
+ * @shutdown:          shut down the interrupt (defaults to ->disable if NULL)
+ * @enable:            enable the interrupt (defaults to chip->unmask if NULL)
+ * @disable:           disable the interrupt (defaults to chip->mask if NULL)
+ * @ack:               start of a new interrupt
+ * @mask:              mask an interrupt source
+ * @mask_ack:          ack and mask an interrupt source
+ * @unmask:            unmask an interrupt source
+ * @eoi:               end of interrupt - chip level
+ * @end:               end of interrupt - flow level
+ * @set_affinity:      set the CPU affinity on SMP machines
+ * @retrigger:         resend an IRQ to the CPU
+ * @set_type:          set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
+ * @set_wake:          enable/disable power-management wake-on of an IRQ
+ *
+ * @release:           release function solely used by UML
+ * @typename:          obsoleted by name, kept as migration helper
+ */
+struct irq_chip {
+       const char      *name;
+       unsigned int    (*startup)(unsigned int irq);
+       void            (*shutdown)(unsigned int irq);
+       void            (*enable)(unsigned int irq);
+       void            (*disable)(unsigned int irq);
+
+       void            (*ack)(unsigned int irq);
+       void            (*mask)(unsigned int irq);
+       void            (*mask_ack)(unsigned int irq);
+       void            (*unmask)(unsigned int irq);
+       void            (*eoi)(unsigned int irq);
+
+       void            (*end)(unsigned int irq);
+       void            (*set_affinity)(unsigned int irq, cpumask_t dest);
+       int             (*retrigger)(unsigned int irq);
+       int             (*set_type)(unsigned int irq, unsigned int flow_type);
+       int             (*set_wake)(unsigned int irq, unsigned int on);
+
        /* Currently used only by UML, might disappear one day.*/
 #ifdef CONFIG_IRQ_RELEASE_METHOD
-       void (*release)(unsigned int irq, void *dev_id);
+       void            (*release)(unsigned int irq, void *dev_id);
 #endif
+       /*
+        * For compatibility, ->typename is copied into ->name.
+        * Will disappear.
+        */
+       const char      *typename;
 };
 
-typedef struct hw_interrupt_type  hw_irq_controller;
-
-/*
- * This is the "IRQ descriptor", which contains various information
- * about the irq, including what kind of hardware handling it has,
- * whether it is disabled etc etc.
+/**
+ * struct irq_desc - interrupt descriptor
+ *
+ * @handle_irq:                highlevel irq-events handler [if NULL, __do_IRQ()]
+ * @chip:              low level interrupt hardware access
+ * @handler_data:      per-IRQ data for the irq_chip methods
+ * @chip_data:         platform-specific per-chip private data for the chip
+ *                     methods, to allow shared chip implementations
+ * @action:            the irq action chain
+ * @status:            status information
+ * @depth:             disable-depth, for nested irq_disable() calls
+ * @irq_count:         stats field to detect stalled irqs
+ * @irqs_unhandled:    stats field for spurious unhandled interrupts
+ * @lock:              locking for SMP
+ * @affinity:          IRQ affinity on SMP
+ * @cpu:               cpu index useful for balancing
+ * @pending_mask:      pending rebalanced interrupts
+ * @move_irq:          need to re-target IRQ destination
+ * @dir:               /proc/irq/ procfs entry
+ * @affinity_entry:    /proc/irq/smp_affinity procfs entry on SMP
  *
  * Pad this out to 32 bytes for cache and indexing reasons.
  */
-typedef struct irq_desc {
-       hw_irq_controller *handler;
-       void *handler_data;
-       struct irqaction *action;       /* IRQ action list */
-       unsigned int status;            /* IRQ status */
-       unsigned int depth;             /* nested irq disables */
-       unsigned int irq_count;         /* For detecting broken interrupts */
-       unsigned int irqs_unhandled;
-       spinlock_t lock;
-#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
-       unsigned int move_irq;          /* Flag need to re-target intr dest*/
+struct irq_desc {
+       void fastcall           (*handle_irq)(unsigned int irq,
+                                             struct irq_desc *desc,
+                                             struct pt_regs *regs);
+       struct irq_chip         *chip;
+       void                    *handler_data;
+       void                    *chip_data;
+       struct irqaction        *action;        /* IRQ action list */
+       unsigned int            status;         /* IRQ status */
+
+       unsigned int            depth;          /* nested irq disables */
+       unsigned int            irq_count;      /* For detecting broken IRQs */
+       unsigned int            irqs_unhandled;
+       spinlock_t              lock;
+#ifdef CONFIG_SMP
+       cpumask_t               affinity;
+       unsigned int            cpu;
+#endif
+#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
+       cpumask_t               pending_mask;
+       unsigned int            move_irq;       /* need to re-target IRQ dest */
 #endif
-} ____cacheline_aligned irq_desc_t;
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *dir;
+#endif
+} ____cacheline_aligned;
 
-extern irq_desc_t irq_desc [NR_IRQS];
+extern struct irq_desc irq_desc[NR_IRQS];
 
-/* Return a pointer to the irq descriptor for IRQ.  */
-static inline irq_desc_t *
-irq_descp (int irq)
-{
-       return irq_desc + irq;
-}
+/*
+ * Migration helpers for obsolete names, they will go away:
+ */
+#define hw_interrupt_type      irq_chip
+typedef struct irq_chip                hw_irq_controller;
+#define no_irq_type            no_irq_chip
+typedef struct irq_desc                irq_desc_t;
 
-#include <asm/hw_irq.h> /* the arch dependent stuff */
+/*
+ * Pick up the arch-dependent methods:
+ */
+#include <asm/hw_irq.h>
 
-extern int setup_irq(unsigned int irq, struct irqaction * new);
+extern int setup_irq(unsigned int irq, struct irqaction *new);
 
 #ifdef CONFIG_GENERIC_HARDIRQS
-extern cpumask_t irq_affinity[NR_IRQS];
 
 #ifdef CONFIG_SMP
 static inline void set_native_irq_info(int irq, cpumask_t mask)
 {
-       irq_affinity[irq] = mask;
+       irq_desc[irq].affinity = mask;
 }
 #else
 static inline void set_native_irq_info(int irq, cpumask_t mask)
@@ -111,8 +196,7 @@ static inline void set_native_irq_info(int irq, cpumask_t mask)
 
 #ifdef CONFIG_SMP
 
-#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
-extern cpumask_t pending_irq_cpumask[NR_IRQS];
+#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
 
 void set_pending_irq(unsigned int irq, cpumask_t mask);
 void move_native_irq(int irq);
@@ -133,7 +217,7 @@ static inline void set_irq_info(int irq, cpumask_t mask)
 {
 }
 
-#else // CONFIG_PCI_MSI
+#else /* CONFIG_PCI_MSI */
 
 static inline void move_irq(int irq)
 {
@@ -144,26 +228,36 @@ static inline void set_irq_info(int irq, cpumask_t mask)
 {
        set_native_irq_info(irq, mask);
 }
-#endif // CONFIG_PCI_MSI
 
-#else  // CONFIG_GENERIC_PENDING_IRQ || CONFIG_IRQBALANCE
+#endif /* CONFIG_PCI_MSI */
+
+#else /* CONFIG_GENERIC_PENDING_IRQ || CONFIG_IRQBALANCE */
+
+static inline void move_irq(int irq)
+{
+}
+
+static inline void move_native_irq(int irq)
+{
+}
+
+static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
+{
+}
 
-#define move_irq(x)
-#define move_native_irq(x)
-#define set_pending_irq(x,y)
 static inline void set_irq_info(int irq, cpumask_t mask)
 {
        set_native_irq_info(irq, mask);
 }
 
-#endif // CONFIG_GENERIC_PENDING_IRQ
+#endif /* CONFIG_GENERIC_PENDING_IRQ */
 
-#else // CONFIG_SMP
+#else /* CONFIG_SMP */
 
 #define move_irq(x)
 #define move_native_irq(x)
 
-#endif // CONFIG_SMP
+#endif /* CONFIG_SMP */
 
 #ifdef CONFIG_IRQBALANCE
 extern void set_balance_irq_affinity(unsigned int irq, cpumask_t mask);
@@ -173,32 +267,138 @@ static inline void set_balance_irq_affinity(unsigned int irq, cpumask_t mask)
 }
 #endif
 
+#ifdef CONFIG_AUTO_IRQ_AFFINITY
+extern int select_smp_affinity(unsigned int irq);
+#else
+static inline int select_smp_affinity(unsigned int irq)
+{
+       return 1;
+}
+#endif
+
 extern int no_irq_affinity;
-extern int noirqdebug_setup(char *str);
 
-extern fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
-                                       struct irqaction *action);
+/* Handle irq action chains: */
+extern int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+                           struct irqaction *action);
+
+/*
+ * Built-in IRQ handlers for various IRQ types,
+ * callable via desc->chip->handle_irq()
+ */
+extern void fastcall
+handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
+extern void fastcall
+handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc,
+                        struct pt_regs *regs);
+extern void fastcall
+handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
+extern void fastcall
+handle_simple_irq(unsigned int irq, struct irq_desc *desc,
+                 struct pt_regs *regs);
+extern void fastcall
+handle_percpu_irq(unsigned int irq, struct irq_desc *desc,
+                 struct pt_regs *regs);
+extern void fastcall
+handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
+
+/*
+ * Get a descriptive string for the highlevel handler, for
+ * /proc/interrupts output:
+ */
+extern const char *
+handle_irq_name(void fastcall (*handle)(unsigned int, struct irq_desc *,
+                                       struct pt_regs *));
+
+/*
+ * Monolithic do_IRQ implementation.
+ * (is an explicit fastcall, because i386 4KSTACKS calls it from assembly)
+ */
 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, struct pt_regs *regs);
-extern int can_request_irq(unsigned int irq, unsigned long irqflags);
 
+/*
+ * Architectures call this to let the generic IRQ layer
+ * handle an interrupt. If the descriptor is attached to an
+ * irqchip-style controller then we call the ->handle_irq() handler,
+ * and it calls __do_IRQ() if it's attached to an irqtype-style controller.
+ */
+static inline void generic_handle_irq(unsigned int irq, struct pt_regs *regs)
+{
+       struct irq_desc *desc = irq_desc + irq;
+
+       if (likely(desc->handle_irq))
+               desc->handle_irq(irq, desc, regs);
+       else
+               __do_IRQ(irq, regs);
+}
+
+/* Handling of unhandled and spurious interrupts: */
+extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
+                          int action_ret, struct pt_regs *regs);
+
+/* Resending of interrupts :*/
+void check_irq_resend(struct irq_desc *desc, unsigned int irq);
+
+/* Initialize /proc/irq/ */
 extern void init_irq_proc(void);
 
-#ifdef CONFIG_AUTO_IRQ_AFFINITY
-extern int select_smp_affinity(unsigned int irq);
-#else
-static inline int
-select_smp_affinity(unsigned int irq)
+/* Enable/disable irq debugging output: */
+extern int noirqdebug_setup(char *str);
+
+/* Checks whether the interrupt can be requested by request_irq(): */
+extern int can_request_irq(unsigned int irq, unsigned long irqflags);
+
+/* Dummy irq-chip implementation: */
+extern struct irq_chip no_irq_chip;
+
+extern void
+set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
+                        void fastcall (*handle)(unsigned int,
+                                                struct irq_desc *,
+                                                struct pt_regs *));
+extern void
+__set_irq_handler(unsigned int irq,
+                 void fastcall (*handle)(unsigned int, struct irq_desc *,
+                                         struct pt_regs *),
+                 int is_chained);
+
+/*
+ * Set a highlevel flow handler for a given IRQ:
+ */
+static inline void
+set_irq_handler(unsigned int irq,
+               void fastcall (*handle)(unsigned int, struct irq_desc *,
+                                       struct pt_regs *))
 {
-       return 1;
+       __set_irq_handler(irq, handle, 0);
 }
-#endif
 
-#endif
+/*
+ * Set a highlevel chained flow handler for a given IRQ.
+ * (a chained handler is automatically enabled and set to
+ *  IRQ_NOREQUEST and IRQ_NOPROBE)
+ */
+static inline void
+set_irq_chained_handler(unsigned int irq,
+                       void fastcall (*handle)(unsigned int, struct irq_desc *,
+                                               struct pt_regs *))
+{
+       __set_irq_handler(irq, handle, 1);
+}
 
-extern hw_irq_controller no_irq_type;  /* needed in every arch ? */
+/* Set/get chip/data for an IRQ: */
 
-#endif
+extern int set_irq_chip(unsigned int irq, struct irq_chip *chip);
+extern int set_irq_data(unsigned int irq, void *data);
+extern int set_irq_chip_data(unsigned int irq, void *data);
+extern int set_irq_type(unsigned int irq, unsigned int type);
+
+#define get_irq_chip(irq)      (irq_desc[irq].chip)
+#define get_irq_chip_data(irq) (irq_desc[irq].chip_data)
+#define get_irq_data(irq)      (irq_desc[irq].handler_data)
+
+#endif /* CONFIG_GENERIC_HARDIRQS */
+
+#endif /* !CONFIG_S390 */
 
-#endif /* __irq_h */
+#endif /* _LINUX_IRQ_H */
diff --git a/include/linux/isdn/tpam.h b/include/linux/isdn/tpam.h
deleted file mode 100644 (file)
index d18dd0d..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* $Id: tpam.h,v 1.1.2.1 2001/06/08 08:23:46 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux. (Kernel Driver)
- *
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
- *
- * For all support questions please contact: <support@auvertech.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; 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.
- *
- */
-
-#ifndef _TPAM_H_
-#define _TPAM_H_
-
-#include <linux/types.h>
-
-/* IOCTL commands */
-#define TPAM_CMD_DSPLOAD       0x0001
-#define TPAM_CMD_DSPSAVE       0x0002
-#define TPAM_CMD_DSPRUN                0x0003
-#define TPAM_CMD_LOOPMODEON    0x0004
-#define TPAM_CMD_LOOPMODEOFF   0x0005
-
-/* addresses of debug information zones on board */
-#define TPAM_TRAPAUDIT_REGISTER                0x005493e4
-#define TPAM_NCOAUDIT_REGISTER         0x00500000
-#define TPAM_MSGAUDIT_REGISTER         0x008E30F0
-
-/* length of debug information zones on board */
-#define TPAM_TRAPAUDIT_LENGTH          10000
-#define TPAM_NCOAUDIT_LENGTH           300000
-#define TPAM_NCOAUDIT_COUNT            30
-#define TPAM_MSGAUDIT_LENGTH           60000
-
-/* IOCTL load/save parameter */
-typedef struct tpam_dsp_ioctl {
-       __u32 address;  /* address to load/save data */
-       __u32 data_len; /* size of data to be loaded/saved */
-       __u8 data[0];   /* data */
-} tpam_dsp_ioctl;
-
-#endif /* _TPAM_H_ */
index c6f70660b3716e39736153151cc5ef6c1b82fd70..c9c760700bc3415046d6243a0b7143d1ec173b5c 100644 (file)
@@ -186,6 +186,7 @@ struct jffs2_raw_xref
        jint32_t hdr_crc;
        jint32_t ino;           /* inode number */
        jint32_t xid;           /* XATTR identifier number */
+       jint32_t xseqno;        /* xref sequencial number */
        jint32_t node_crc;
 } __attribute__((packed));
 
index 4eb851ece080d0682f4ada0b9fe24aad22c3cd19..efe0ee4cc80baee508567f08c72b3f7d03277e43 100644 (file)
@@ -155,10 +155,8 @@ static inline void con_schedule_flip(struct tty_struct *t)
 {
        unsigned long flags;
        spin_lock_irqsave(&t->buf.lock, flags);
-       if (t->buf.tail != NULL) {
-               t->buf.tail->active = 0;
+       if (t->buf.tail != NULL)
                t->buf.tail->commit = t->buf.tail->used;
-       }
        spin_unlock_irqrestore(&t->buf.lock, flags);
        schedule_work(&t->buf.work);
 }
index e693e729bc92141b77440c217599e70860a81934..169f05e4863ed140058674a1e5a1fcab5f06f766 100644 (file)
@@ -177,7 +177,8 @@ struct key {
 /*
  * kernel managed key type definition
  */
-typedef int (*request_key_actor_t)(struct key *key, struct key *authkey, const char *op);
+typedef int (*request_key_actor_t)(struct key *key, struct key *authkey,
+                                  const char *op, void *aux);
 
 struct key_type {
        /* name of the type */
@@ -285,6 +286,11 @@ extern struct key *request_key(struct key_type *type,
                               const char *description,
                               const char *callout_info);
 
+extern struct key *request_key_with_auxdata(struct key_type *type,
+                                           const char *description,
+                                           const char *callout_info,
+                                           void *aux);
+
 extern int key_validate(struct key *key);
 
 extern key_ref_t key_create_or_update(key_ref_t keyring,
index 20b1cf527c609a575ff468b91f7a4106a8464a8b..f4284bf897585727ee8b2a6cacafd6e228d28b96 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
+#include <asm/scatterlist.h>
 #include <asm/io.h>
 #include <linux/ata.h>
 #include <linux/workqueue.h>
@@ -887,6 +888,9 @@ static inline unsigned int ata_tag_internal(unsigned int tag)
        return tag == ATA_MAX_QUEUE - 1;
 }
 
+/*
+ * device helpers
+ */
 static inline unsigned int ata_class_enabled(unsigned int class)
 {
        return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI;
@@ -917,6 +921,17 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
        return ata_class_absent(dev->class);
 }
 
+/*
+ * port helpers
+ */
+static inline int ata_port_max_devices(const struct ata_port *ap)
+{
+       if (ap->flags & ATA_FLAG_SLAVE_POSS)
+               return 2;
+       return 1;
+}
+
+
 static inline u8 ata_chk_status(struct ata_port *ap)
 {
        return ap->ops->check_status(ap);
index 37ca31b21bb7a29cda46861f5e3d97a25ed83622..6b74adf5297f644f82531a5fbcbc55b5892d13f7 100644 (file)
@@ -4,17 +4,10 @@
 #ifdef __KERNEL__
 
 #include <linux/stddef.h>
+#include <linux/poison.h>
 #include <linux/prefetch.h>
 #include <asm/system.h>
 
-/*
- * These are non-NULL pointers that will result in page faults
- * under normal circumstances, used to verify that nobody uses
- * non-initialized list entries.
- */
-#define LIST_POISON1  ((void *) 0x00100100)
-#define LIST_POISON2  ((void *) 0x00200200)
-
 /*
  * Simple doubly linked list implementation.
  *
index 911206386171ccedc51397d9e36a7c424de9642c..218501cfaeb9255ed62ca9fbf2a197cbb6993f53 100644 (file)
@@ -63,6 +63,76 @@ extern int online_pages(unsigned long, unsigned long);
 /* reasonably generic interface to expand the physical pages in a zone  */
 extern int __add_pages(struct zone *zone, unsigned long start_pfn,
        unsigned long nr_pages);
+
+#ifdef CONFIG_NUMA
+extern int memory_add_physaddr_to_nid(u64 start);
+#else
+static inline int memory_add_physaddr_to_nid(u64 start)
+{
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_HAVE_ARCH_NODEDATA_EXTENSION
+/*
+ * For supporting node-hotadd, we have to allocate a new pgdat.
+ *
+ * If an arch has generic style NODE_DATA(),
+ * node_data[nid] = kzalloc() works well. But it depends on the architecture.
+ *
+ * In general, generic_alloc_nodedata() is used.
+ * Now, arch_free_nodedata() is just defined for error path of node_hot_add.
+ *
+ */
+extern pg_data_t *arch_alloc_nodedata(int nid);
+extern void arch_free_nodedata(pg_data_t *pgdat);
+extern void arch_refresh_nodedata(int nid, pg_data_t *pgdat);
+
+#else /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */
+
+#define arch_alloc_nodedata(nid)       generic_alloc_nodedata(nid)
+#define arch_free_nodedata(pgdat)      generic_free_nodedata(pgdat)
+
+#ifdef CONFIG_NUMA
+/*
+ * If ARCH_HAS_NODEDATA_EXTENSION=n, this func is used to allocate pgdat.
+ * XXX: kmalloc_node() can't work well to get new node's memory at this time.
+ *     Because, pgdat for the new node is not allocated/initialized yet itself.
+ *     To use new node's memory, more consideration will be necessary.
+ */
+#define generic_alloc_nodedata(nid)                            \
+({                                                             \
+       kzalloc(sizeof(pg_data_t), GFP_KERNEL);                 \
+})
+/*
+ * This definition is just for error path in node hotadd.
+ * For node hotremove, we have to replace this.
+ */
+#define generic_free_nodedata(pgdat)   kfree(pgdat)
+
+extern pg_data_t *node_data[];
+static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
+{
+       node_data[nid] = pgdat;
+}
+
+#else /* !CONFIG_NUMA */
+
+/* never called */
+static inline pg_data_t *generic_alloc_nodedata(int nid)
+{
+       BUG();
+       return NULL;
+}
+static inline void generic_free_nodedata(pg_data_t *pgdat)
+{
+}
+static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
+{
+}
+#endif /* CONFIG_NUMA */
+#endif /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */
+
 #else /* ! CONFIG_MEMORY_HOTPLUG */
 /*
  * Stub functions for when hotplug is off
@@ -99,7 +169,8 @@ static inline int __remove_pages(struct zone *zone, unsigned long start_pfn,
        return -ENOSYS;
 }
 
-extern int add_memory(u64 start, u64 size);
+extern int add_memory(int nid, u64 start, u64 size);
+extern int arch_add_memory(int nid, u64 start, u64 size);
 extern int remove_memory(u64 start, u64 size);
 
 #endif /* __LINUX_MEMORY_HOTPLUG_H */
index 5b584dafb5a6d4384f9b3169b2500d8cf0c3b518..b03cfb91e228dd993987e3b2eb497c832397e073 100644 (file)
@@ -40,7 +40,6 @@ struct miscdevice  {
        struct list_head list;
        struct device *dev;
        struct class_device *class;
-       char devfs_name[64];
 };
 
 extern int misc_register(struct miscdevice * misc);
index a929ea197e4844da5d11fc9f43da506138b276f7..c41a1299b8cf354cc8b9d9677f328aa4bc8b8533 100644 (file)
@@ -1030,13 +1030,20 @@ static inline void vm_stat_account(struct mm_struct *mm,
 }
 #endif /* CONFIG_PROC_FS */
 
+static inline void
+debug_check_no_locks_freed(const void *from, unsigned long len)
+{
+       mutex_debug_check_no_locks_freed(from, len);
+       rt_mutex_debug_check_no_locks_freed(from, len);
+}
+
 #ifndef CONFIG_DEBUG_PAGEALLOC
 static inline void
 kernel_map_pages(struct page *page, int numpages, int enable)
 {
        if (!PageHighMem(page) && !enable)
-               mutex_debug_check_no_locks_freed(page_address(page),
-                                                numpages * PAGE_SIZE);
+               debug_check_no_locks_freed(page_address(page),
+                                          numpages * PAGE_SIZE);
 }
 #endif
 
@@ -1065,5 +1072,7 @@ void drop_slab(void);
 extern int randomize_va_space;
 #endif
 
+const char *arch_vma_name(struct vm_area_struct *vma);
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MM_H */
index 9ebbb74b7b729ee8fe17a8ed783c1a3327944fb8..9e9dc7c24d9589e50e84913c76f46ac9ec3b2ae5 100644 (file)
@@ -203,6 +203,15 @@ void *__symbol_get_gpl(const char *symbol);
 #define EXPORT_SYMBOL_GPL_FUTURE(sym)                          \
        __EXPORT_SYMBOL(sym, "_gpl_future")
 
+
+#ifdef CONFIG_UNUSED_SYMBOLS
+#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
+#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl")
+#else
+#define EXPORT_UNUSED_SYMBOL(sym)
+#define EXPORT_UNUSED_SYMBOL_GPL(sym)
+#endif
+
 #endif
 
 struct module_ref
@@ -261,6 +270,15 @@ struct module
        unsigned int num_gpl_syms;
        const unsigned long *gpl_crcs;
 
+       /* unused exported symbols. */
+       const struct kernel_symbol *unused_syms;
+       unsigned int num_unused_syms;
+       const unsigned long *unused_crcs;
+       /* GPL-only, unused exported symbols. */
+       const struct kernel_symbol *unused_gpl_syms;
+       unsigned int num_unused_gpl_syms;
+       const unsigned long *unused_gpl_crcs;
+
        /* symbols that will be GPL-only in the near future. */
        const struct kernel_symbol *gpl_future_syms;
        unsigned int num_gpl_future_syms;
@@ -456,6 +474,8 @@ void module_remove_driver(struct device_driver *);
 #define EXPORT_SYMBOL(sym)
 #define EXPORT_SYMBOL_GPL(sym)
 #define EXPORT_SYMBOL_GPL_FUTURE(sym)
+#define EXPORT_UNUSED_SYMBOL(sym)
+#define EXPORT_UNUSED_SYMBOL_GPL(sym)
 
 /* Given an address, look for it in the exception tables. */
 static inline const struct exception_table_entry *
index 0a1740b2532ebfe417d9adbdc8703d39d24cca1e..d90b1bb3756305d71303de5e726636fa9f3cdfe1 100644 (file)
@@ -335,7 +335,7 @@ extern struct inode_operations nfs_file_inode_operations;
 extern struct inode_operations nfs3_file_inode_operations;
 #endif /* CONFIG_NFS_V3 */
 extern const struct file_operations nfs_file_operations;
-extern struct address_space_operations nfs_file_aops;
+extern const struct address_space_operations nfs_file_aops;
 
 static inline struct rpc_cred *nfs_file_cred(struct file *file)
 {
index 254dc3de650b81e5cce4821f8101dad72005f996..81dcec84cd8f00290037cb29c7f7e0960b51b895 100644 (file)
@@ -26,8 +26,25 @@ struct node {
        struct sys_device       sysdev;
 };
 
+extern struct node node_devices[];
+
 extern int register_node(struct node *, int, struct node *);
 extern void unregister_node(struct node *node);
+extern int register_one_node(int nid);
+extern void unregister_one_node(int nid);
+#ifdef CONFIG_NUMA
+extern int register_cpu_under_node(unsigned int cpu, unsigned int nid);
+extern int unregister_cpu_under_node(unsigned int cpu, unsigned int nid);
+#else
+static inline int register_cpu_under_node(unsigned int cpu, unsigned int nid)
+{
+       return 0;
+}
+static inline int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
+{
+       return 0;
+}
+#endif
 
 #define to_node(sys_device) container_of(sys_device, struct node, sysdev)
 
diff --git a/include/linux/nsc_gpio.h b/include/linux/nsc_gpio.h
new file mode 100644 (file)
index 0000000..135742c
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+   nsc_gpio.c
+
+   National Semiconductor GPIO common access methods.
+
+   struct nsc_gpio_ops abstracts the low-level access
+   operations for the GPIO units on 2 NSC chip families; the GEODE
+   integrated CPU, and the PC-8736[03456] integrated PC-peripheral
+   chips.
+
+   The GPIO units on these chips have the same pin architecture, but
+   the access methods differ.  Thus, scx200_gpio and pc8736x_gpio
+   implement their own versions of these routines; and use the common
+   file-operations routines implemented in nsc_gpio module.
+
+   Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com>
+
+   NB: this work was tested on the Geode SC-1100 and PC-87366 chips.
+   NSC sold the GEODE line to AMD, and the PC-8736x line to Winbond.
+*/
+
+struct nsc_gpio_ops {
+       struct module*  owner;
+       u32     (*gpio_config)  (unsigned iminor, u32 mask, u32 bits);
+       void    (*gpio_dump)    (struct nsc_gpio_ops *amp, unsigned iminor);
+       int     (*gpio_get)     (unsigned iminor);
+       void    (*gpio_set)     (unsigned iminor, int state);
+       void    (*gpio_set_high)(unsigned iminor);
+       void    (*gpio_set_low) (unsigned iminor);
+       void    (*gpio_change)  (unsigned iminor);
+       int     (*gpio_current) (unsigned iminor);
+       struct device*  dev;    /* for dev_dbg() support, set in init  */
+};
+
+extern ssize_t nsc_gpio_write(struct file *file, const char __user *data,
+                             size_t len, loff_t *ppos);
+
+extern ssize_t nsc_gpio_read(struct file *file, char __user *buf,
+                            size_t len, loff_t *ppos);
+
+extern void nsc_gpio_dump(struct nsc_gpio_ops *amp, unsigned index);
+
index 62a8c22f5f604981970a762d780c0f9eff101165..983fca251b25c67bfc23c738d282eb09a411602b 100644 (file)
@@ -404,8 +404,8 @@ int pcibios_enable_device(struct pci_dev *, int mask);
 char *pcibios_setup (char *str);
 
 /* Used only when drivers/pci/setup.c is used */
-void pcibios_align_resource(void *, struct resource *,
-                           unsigned long, unsigned long);
+void pcibios_align_resource(void *, struct resource *, resource_size_t,
+                               resource_size_t);
 void pcibios_update_irq(struct pci_dev *, int irq);
 
 /* Generic PCI functions used internally */
@@ -532,10 +532,10 @@ void pci_release_region(struct pci_dev *, int);
 
 /* drivers/pci/bus.c */
 int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
-                          unsigned long size, unsigned long align,
-                          unsigned long min, unsigned int type_mask,
+                          resource_size_t size, resource_size_t align,
+                          resource_size_t min, unsigned int type_mask,
                           void (*alignf)(void *, struct resource *,
-                                         unsigned long, unsigned long),
+                                         resource_size_t, resource_size_t),
                           void *alignf_data);
 void pci_enable_bridges(struct pci_bus *bus);
 
@@ -730,7 +730,8 @@ static inline char *pci_name(struct pci_dev *pdev)
  */
 #ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER
 static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
-                const struct resource *rsrc, u64 *start, u64 *end)
+                const struct resource *rsrc, resource_size_t *start,
+               resource_size_t *end)
 {
        *start = rsrc->start;
        *end = rsrc->end;
index c2fd2d19938b94931303ed9e538b235a69494687..9ae6b1a753668e74155316473c7b5adcbe5da209 100644 (file)
 #define PCI_DEVICE_ID_NVIDIA_NVENET_19              0x03EF
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2     0x03F6
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3     0x03F7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE      0x0448
 #define PCI_DEVICE_ID_NVIDIA_NVENET_20              0x0450
 #define PCI_DEVICE_ID_NVIDIA_NVENET_21              0x0451
 #define PCI_DEVICE_ID_NVIDIA_NVENET_22              0x0452
 #define PCI_DEVICE_ID_INTEL_ICH8_4     0x2815
 #define PCI_DEVICE_ID_INTEL_ICH8_5     0x283e
 #define PCI_DEVICE_ID_INTEL_ICH8_6     0x2850
-#define PCI_DEVICE_ID_INTEL_GD31244    0x3200
 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340
 #define PCI_DEVICE_ID_INTEL_82830_HB   0x3575
 #define PCI_DEVICE_ID_INTEL_82830_CGC  0x3577
diff --git a/include/linux/plist.h b/include/linux/plist.h
new file mode 100644 (file)
index 0000000..b95818a
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Descending-priority-sorted double-linked list
+ *
+ * (C) 2002-2003 Intel Corp
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
+ *
+ * 2001-2005 (c) MontaVista Software, Inc.
+ * Daniel Walker <dwalker@mvista.com>
+ *
+ * (C) 2005 Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Simplifications of the original code by
+ * Oleg Nesterov <oleg@tv-sign.ru>
+ *
+ * Licensed under the FSF's GNU Public License v2 or later.
+ *
+ * Based on simple lists (include/linux/list.h).
+ *
+ * This is a priority-sorted list of nodes; each node has a
+ * priority from INT_MIN (highest) to INT_MAX (lowest).
+ *
+ * Addition is O(K), removal is O(1), change of priority of a node is
+ * O(K) and K is the number of RT priority levels used in the system.
+ * (1 <= K <= 99)
+ *
+ * This list is really a list of lists:
+ *
+ *  - The tier 1 list is the prio_list, different priority nodes.
+ *
+ *  - The tier 2 list is the node_list, serialized nodes.
+ *
+ * Simple ASCII art explanation:
+ *
+ * |HEAD          |
+ * |              |
+ * |prio_list.prev|<------------------------------------|
+ * |prio_list.next|<->|pl|<->|pl|<--------------->|pl|<-|
+ * |10            |   |10|   |21|   |21|   |21|   |40|   (prio)
+ * |              |   |  |   |  |   |  |   |  |   |  |
+ * |              |   |  |   |  |   |  |   |  |   |  |
+ * |node_list.next|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
+ * |node_list.prev|<------------------------------------|
+ *
+ * The nodes on the prio_list list are sorted by priority to simplify
+ * the insertion of new nodes. There are no nodes with duplicate
+ * priorites on the list.
+ *
+ * The nodes on the node_list is ordered by priority and can contain
+ * entries which have the same priority. Those entries are ordered
+ * FIFO
+ *
+ * Addition means: look for the prio_list node in the prio_list
+ * for the priority of the node and insert it before the node_list
+ * entry of the next prio_list node. If it is the first node of
+ * that priority, add it to the prio_list in the right position and
+ * insert it into the serialized node_list list
+ *
+ * Removal means remove it from the node_list and remove it from
+ * the prio_list if the node_list list_head is non empty. In case
+ * of removal from the prio_list it must be checked whether other
+ * entries of the same priority are on the list or not. If there
+ * is another entry of the same priority then this entry has to
+ * replace the removed entry on the prio_list. If the entry which
+ * is removed is the only entry of this priority then a simple
+ * remove from both list is sufficient.
+ *
+ * INT_MIN is the highest priority, 0 is the medium highest, INT_MAX
+ * is lowest priority.
+ *
+ * No locking is done, up to the caller.
+ *
+ */
+#ifndef _LINUX_PLIST_H_
+#define _LINUX_PLIST_H_
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock_types.h>
+
+struct plist_head {
+       struct list_head prio_list;
+       struct list_head node_list;
+#ifdef CONFIG_DEBUG_PI_LIST
+       spinlock_t *lock;
+#endif
+};
+
+struct plist_node {
+       int                     prio;
+       struct plist_head       plist;
+};
+
+#ifdef CONFIG_DEBUG_PI_LIST
+# define PLIST_HEAD_LOCK_INIT(_lock)   .lock = _lock
+#else
+# define PLIST_HEAD_LOCK_INIT(_lock)
+#endif
+
+/**
+ * #PLIST_HEAD_INIT - static struct plist_head initializer
+ *
+ * @head:      struct plist_head variable name
+ */
+#define PLIST_HEAD_INIT(head, _lock)                   \
+{                                                      \
+       .prio_list = LIST_HEAD_INIT((head).prio_list),  \
+       .node_list = LIST_HEAD_INIT((head).node_list),  \
+       PLIST_HEAD_LOCK_INIT(&(_lock))                  \
+}
+
+/**
+ * #PLIST_NODE_INIT - static struct plist_node initializer
+ *
+ * @node:      struct plist_node variable name
+ * @__prio:    initial node priority
+ */
+#define PLIST_NODE_INIT(node, __prio)                  \
+{                                                      \
+       .prio  = (__prio),                              \
+       .plist = PLIST_HEAD_INIT((node).plist, NULL),   \
+}
+
+/**
+ * plist_head_init - dynamic struct plist_head initializer
+ *
+ * @head:      &struct plist_head pointer
+ */
+static inline void
+plist_head_init(struct plist_head *head, spinlock_t *lock)
+{
+       INIT_LIST_HEAD(&head->prio_list);
+       INIT_LIST_HEAD(&head->node_list);
+#ifdef CONFIG_DEBUG_PI_LIST
+       head->lock = lock;
+#endif
+}
+
+/**
+ * plist_node_init - Dynamic struct plist_node initializer
+ *
+ * @node:      &struct plist_node pointer
+ * @prio:      initial node priority
+ */
+static inline void plist_node_init(struct plist_node *node, int prio)
+{
+       node->prio = prio;
+       plist_head_init(&node->plist, NULL);
+}
+
+extern void plist_add(struct plist_node *node, struct plist_head *head);
+extern void plist_del(struct plist_node *node, struct plist_head *head);
+
+/**
+ * plist_for_each - iterate over the plist
+ *
+ * @pos1:      the type * to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define plist_for_each(pos, head)      \
+        list_for_each_entry(pos, &(head)->node_list, plist.node_list)
+
+/**
+ * plist_for_each_entry_safe - iterate over a plist of given type safe
+ * against removal of list entry
+ *
+ * @pos1:      the type * to use as a loop counter.
+ * @n1:        another type * to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define plist_for_each_safe(pos, n, head)      \
+        list_for_each_entry_safe(pos, n, &(head)->node_list, plist.node_list)
+
+/**
+ * plist_for_each_entry        - iterate over list of given type
+ *
+ * @pos:       the type * to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define plist_for_each_entry(pos, head, mem)   \
+        list_for_each_entry(pos, &(head)->node_list, mem.plist.node_list)
+
+/**
+ * plist_for_each_entry_safe - iterate over list of given type safe against
+ * removal of list entry
+ *
+ * @pos:       the type * to use as a loop counter.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @m:         the name of the list_struct within the struct.
+ */
+#define plist_for_each_entry_safe(pos, n, head, m)     \
+       list_for_each_entry_safe(pos, n, &(head)->node_list, m.plist.node_list)
+
+/**
+ * plist_head_empty - return !0 if a plist_head is empty
+ *
+ * @head:      &struct plist_head pointer
+ */
+static inline int plist_head_empty(const struct plist_head *head)
+{
+       return list_empty(&head->node_list);
+}
+
+/**
+ * plist_node_empty - return !0 if plist_node is not on a list
+ *
+ * @node:      &struct plist_node pointer
+ */
+static inline int plist_node_empty(const struct plist_node *node)
+{
+       return plist_head_empty(&node->plist);
+}
+
+/* All functions below assume the plist_head is not empty. */
+
+/**
+ * plist_first_entry - get the struct for the first entry
+ *
+ * @ptr:       the &struct plist_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
+#ifdef CONFIG_DEBUG_PI_LIST
+# define plist_first_entry(head, type, member) \
+({ \
+       WARN_ON(plist_head_empty(head)); \
+       container_of(plist_first(head), type, member); \
+})
+#else
+# define plist_first_entry(head, type, member) \
+       container_of(plist_first(head), type, member)
+#endif
+
+/**
+ * plist_first - return the first node (and thus, highest priority)
+ *
+ * @head:      the &struct plist_head pointer
+ *
+ * Assumes the plist is _not_ empty.
+ */
+static inline struct plist_node* plist_first(const struct plist_head *head)
+{
+       return list_entry(head->node_list.next,
+                         struct plist_node, plist.node_list);
+}
+
+#endif
index 93b0959eb40f466ba0e1834da22c558b090a937e..ab8a8dd8d64c5f55c88bd28c05d7439875239b72 100644 (file)
@@ -389,7 +389,8 @@ int pnp_start_dev(struct pnp_dev *dev);
 int pnp_stop_dev(struct pnp_dev *dev);
 int pnp_activate_dev(struct pnp_dev *dev);
 int pnp_disable_dev(struct pnp_dev *dev);
-void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size);
+void pnp_resource_change(struct resource *resource, resource_size_t start,
+                               resource_size_t size);
 
 /* protocol helpers */
 int pnp_is_active(struct pnp_dev * dev);
@@ -434,7 +435,9 @@ static inline int pnp_start_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_stop_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
-static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { }
+static inline void pnp_resource_change(struct resource *resource,
+                                       resource_size_t start,
+                                       resource_size_t size) { }
 
 /* protocol helpers */
 static inline int pnp_is_active(struct pnp_dev * dev) { return 0; }
diff --git a/include/linux/poison.h b/include/linux/poison.h
new file mode 100644 (file)
index 0000000..a5347c0
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef _LINUX_POISON_H
+#define _LINUX_POISON_H
+
+/********** include/linux/list.h **********/
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+/********** mm/slab.c **********/
+/*
+ * Magic nums for obj red zoning.
+ * Placed in the first word before and the first word after an obj.
+ */
+#define        RED_INACTIVE    0x5A2CF071UL    /* when obj is inactive */
+#define        RED_ACTIVE      0x170FC2A5UL    /* when obj is active */
+
+/* ...and for poisoning */
+#define        POISON_INUSE    0x5a    /* for use-uninitialised poisoning */
+#define POISON_FREE    0x6b    /* for use-after-free poisoning */
+#define        POISON_END      0xa5    /* end-byte of poisoning */
+
+/********** arch/$ARCH/mm/init.c **********/
+#define POISON_FREE_INITMEM    0xcc
+
+/********** arch/x86_64/mm/init.c **********/
+#define        POISON_FREE_INITDATA    0xba
+
+/********** arch/ia64/hp/common/sba_iommu.c **********/
+/*
+ * arch/ia64/hp/common/sba_iommu.c uses a 16-byte poison string with a
+ * value of "SBAIOMMU POISON\0" for spill-over poisoning.
+ */
+
+/********** fs/jbd/journal.c **********/
+#define JBD_POISON_FREE        0x5b
+
+/********** drivers/base/dmapool.c **********/
+#define        POOL_POISON_FREED       0xa7    /* !inuse */
+#define        POOL_POISON_ALLOCATED   0xa9    /* !initted */
+
+/********** drivers/atm/ **********/
+#define ATM_POISON_FREE                0x12
+
+/********** kernel/mutexes **********/
+#define MUTEX_DEBUG_INIT       0x11
+#define MUTEX_DEBUG_FREE       0x22
+
+/********** security/ **********/
+#define KEY_DESTROY            0xbd
+
+/********** sound/oss/ **********/
+#define OSS_POISON_FREE                0xAB
+
+#endif
index 6312758393b61a3e3e741825f78d49956024ea26..48dfe00070c70bbcd27574870b19288f7655364c 100644 (file)
@@ -258,6 +258,7 @@ extern void rcu_init(void);
 extern void rcu_check_callbacks(int cpu, int user);
 extern void rcu_restart_cpu(int cpu);
 extern long rcu_batches_completed(void);
+extern long rcu_batches_completed_bh(void);
 
 /* Exported interfaces */
 extern void FASTCALL(call_rcu(struct rcu_head *head, 
index 5676c4210e2c186d23548072abaf39d5885d4874..daa2d83cefe832a541f6e3ec1f5bd62f01b34c56 100644 (file)
@@ -1973,7 +1973,7 @@ void reiserfs_unmap_buffer(struct buffer_head *);
 /* file.c */
 extern struct inode_operations reiserfs_file_inode_operations;
 extern const struct file_operations reiserfs_file_operations;
-extern struct address_space_operations reiserfs_address_space_operations;
+extern const struct address_space_operations reiserfs_address_space_operations;
 
 /* fix_nodes.c */
 
diff --git a/include/linux/rtmutex.h b/include/linux/rtmutex.h
new file mode 100644 (file)
index 0000000..fa4a3b8
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * RT Mutexes: blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner:
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ * This file contains the public data structure and API definitions.
+ */
+
+#ifndef __LINUX_RT_MUTEX_H
+#define __LINUX_RT_MUTEX_H
+
+#include <linux/linkage.h>
+#include <linux/plist.h>
+#include <linux/spinlock_types.h>
+
+/*
+ * The rt_mutex structure
+ *
+ * @wait_lock: spinlock to protect the structure
+ * @wait_list: pilist head to enqueue waiters in priority order
+ * @owner:     the mutex owner
+ */
+struct rt_mutex {
+       spinlock_t              wait_lock;
+       struct plist_head       wait_list;
+       struct task_struct      *owner;
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+       int                     save_state;
+       struct list_head        held_list_entry;
+       unsigned long           acquire_ip;
+       const char              *name, *file;
+       int                     line;
+       void                    *magic;
+#endif
+};
+
+struct rt_mutex_waiter;
+struct hrtimer_sleeper;
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+ extern int rt_mutex_debug_check_no_locks_freed(const void *from,
+                                               unsigned long len);
+ extern void rt_mutex_debug_check_no_locks_held(struct task_struct *task);
+#else
+ static inline int rt_mutex_debug_check_no_locks_freed(const void *from,
+                                                      unsigned long len)
+ {
+       return 0;
+ }
+# define rt_mutex_debug_check_no_locks_held(task)      do { } while (0)
+#endif
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname) \
+       , .name = #mutexname, .file = __FILE__, .line = __LINE__
+# define rt_mutex_init(mutex)                  __rt_mutex_init(mutex, __FUNCTION__)
+ extern void rt_mutex_debug_task_free(struct task_struct *tsk);
+#else
+# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname)
+# define rt_mutex_init(mutex)                  __rt_mutex_init(mutex, NULL)
+# define rt_mutex_debug_task_free(t)                   do { } while (0)
+#endif
+
+#define __RT_MUTEX_INITIALIZER(mutexname) \
+       { .wait_lock = SPIN_LOCK_UNLOCKED \
+       , .wait_list = PLIST_HEAD_INIT(mutexname.wait_list, mutexname.wait_lock) \
+       , .owner = NULL \
+       __DEBUG_RT_MUTEX_INITIALIZER(mutexname)}
+
+#define DEFINE_RT_MUTEX(mutexname) \
+       struct rt_mutex mutexname = __RT_MUTEX_INITIALIZER(mutexname)
+
+/***
+ * rt_mutex_is_locked - is the mutex locked
+ * @lock: the mutex to be queried
+ *
+ * Returns 1 if the mutex is locked, 0 if unlocked.
+ */
+static inline int rt_mutex_is_locked(struct rt_mutex *lock)
+{
+       return lock->owner != NULL;
+}
+
+extern void __rt_mutex_init(struct rt_mutex *lock, const char *name);
+extern void rt_mutex_destroy(struct rt_mutex *lock);
+
+extern void rt_mutex_lock(struct rt_mutex *lock);
+extern int rt_mutex_lock_interruptible(struct rt_mutex *lock,
+                                               int detect_deadlock);
+extern int rt_mutex_timed_lock(struct rt_mutex *lock,
+                                       struct hrtimer_sleeper *timeout,
+                                       int detect_deadlock);
+
+extern int rt_mutex_trylock(struct rt_mutex *lock);
+
+extern void rt_mutex_unlock(struct rt_mutex *lock);
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# define INIT_RT_MUTEX_DEBUG(tsk)                                      \
+       .held_list_head = LIST_HEAD_INIT(tsk.held_list_head),           \
+       .held_list_lock = SPIN_LOCK_UNLOCKED
+#else
+# define INIT_RT_MUTEX_DEBUG(tsk)
+#endif
+
+#ifdef CONFIG_RT_MUTEXES
+# define INIT_RT_MUTEXES(tsk)                                          \
+       .pi_waiters     = PLIST_HEAD_INIT(tsk.pi_waiters, tsk.pi_lock), \
+       INIT_RT_MUTEX_DEBUG(tsk)
+#else
+# define INIT_RT_MUTEXES(tsk)
+#endif
+
+#endif
index 122a25c1b997e46641b636db8a740ca9af9e3788..821f0481ebe190c0b5e171a4e6ab887802b3015c 100644 (file)
@@ -73,6 +73,7 @@ struct sched_param {
 #include <linux/seccomp.h>
 #include <linux/rcupdate.h>
 #include <linux/futex.h>
+#include <linux/rtmutex.h>
 
 #include <linux/time.h>
 #include <linux/param.h>
@@ -83,6 +84,7 @@ struct sched_param {
 #include <asm/processor.h>
 
 struct exec_domain;
+struct futex_pi_state;
 
 /*
  * List of flags we want to share for kernel threads,
@@ -123,6 +125,7 @@ extern unsigned long nr_running(void);
 extern unsigned long nr_uninterruptible(void);
 extern unsigned long nr_active(void);
 extern unsigned long nr_iowait(void);
+extern unsigned long weighted_cpuload(const int cpu);
 
 
 /*
@@ -494,8 +497,11 @@ struct signal_struct {
 
 #define MAX_PRIO               (MAX_RT_PRIO + 40)
 
-#define rt_task(p)             (unlikely((p)->prio < MAX_RT_PRIO))
+#define rt_prio(prio)          unlikely((prio) < MAX_RT_PRIO)
+#define rt_task(p)             rt_prio((p)->prio)
 #define batch_task(p)          (unlikely((p)->policy == SCHED_BATCH))
+#define has_rt_policy(p) \
+       unlikely((p)->policy != SCHED_NORMAL && (p)->policy != SCHED_BATCH)
 
 /*
  * Some day this will be a full-fledged user tracking system..
@@ -558,9 +564,9 @@ enum idle_type
 /*
  * sched-domains (multiprocessor balancing) declarations:
  */
-#ifdef CONFIG_SMP
 #define SCHED_LOAD_SCALE       128UL   /* increase resolution of load */
 
+#ifdef CONFIG_SMP
 #define SD_LOAD_BALANCE                1       /* Do load balancing on this domain. */
 #define SD_BALANCE_NEWIDLE     2       /* Balance when about to become idle */
 #define SD_BALANCE_EXEC                4       /* Balance on exec */
@@ -569,6 +575,11 @@ enum idle_type
 #define SD_WAKE_AFFINE         32      /* Wake task to waking CPU */
 #define SD_WAKE_BALANCE                64      /* Perform balancing at task wakeup */
 #define SD_SHARE_CPUPOWER      128     /* Domain members share cpu power */
+#define SD_POWERSAVINGS_BALANCE        256     /* Balance for power savings */
+
+#define BALANCE_FOR_POWER      ((sched_mc_power_savings || sched_smt_power_savings) \
+                                ? SD_POWERSAVINGS_BALANCE : 0)
+
 
 struct sched_group {
        struct sched_group *next;       /* Must be a circular list */
@@ -638,7 +649,7 @@ struct sched_domain {
 #endif
 };
 
-extern void partition_sched_domains(cpumask_t *partition1,
+extern int partition_sched_domains(cpumask_t *partition1,
                                    cpumask_t *partition2);
 
 /*
@@ -713,10 +724,13 @@ struct task_struct {
 
        int lock_depth;         /* BKL lock depth */
 
-#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
+#ifdef CONFIG_SMP
+#ifdef __ARCH_WANT_UNLOCKED_CTXSW
        int oncpu;
 #endif
-       int prio, static_prio;
+#endif
+       int load_weight;        /* for niceness load balancing purposes */
+       int prio, static_prio, normal_prio;
        struct list_head run_list;
        prio_array_t *array;
 
@@ -843,6 +857,20 @@ struct task_struct {
 /* Protection of (de-)allocation: mm, files, fs, tty, keyrings */
        spinlock_t alloc_lock;
 
+       /* Protection of the PI data structures: */
+       spinlock_t pi_lock;
+
+#ifdef CONFIG_RT_MUTEXES
+       /* PI waiters blocked on a rt_mutex held by this task */
+       struct plist_head pi_waiters;
+       /* Deadlock detection and priority inheritance handling */
+       struct rt_mutex_waiter *pi_blocked_on;
+# ifdef CONFIG_DEBUG_RT_MUTEXES
+       spinlock_t held_list_lock;
+       struct list_head held_list_head;
+# endif
+#endif
+
 #ifdef CONFIG_DEBUG_MUTEXES
        /* mutex deadlock detection */
        struct mutex_waiter *blocked_on;
@@ -888,6 +916,8 @@ struct task_struct {
 #ifdef CONFIG_COMPAT
        struct compat_robust_list_head __user *compat_robust_list;
 #endif
+       struct list_head pi_state_list;
+       struct futex_pi_state *pi_state_cache;
 
        atomic_t fs_excl;       /* holding fs exclusive resources */
        struct rcu_head rcu;
@@ -955,6 +985,7 @@ static inline void put_task_struct(struct task_struct *t)
 #define PF_SPREAD_PAGE 0x01000000      /* Spread page cache over cpuset */
 #define PF_SPREAD_SLAB 0x02000000      /* Spread some slab caches over cpuset */
 #define PF_MEMPOLICY   0x10000000      /* Non-default NUMA mempolicy */
+#define PF_MUTEX_TESTER        0x20000000      /* Thread belongs to the rt mutex tester */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
@@ -1009,6 +1040,19 @@ static inline void idle_task_exit(void) {}
 #endif
 
 extern void sched_idle_next(void);
+
+#ifdef CONFIG_RT_MUTEXES
+extern int rt_mutex_getprio(task_t *p);
+extern void rt_mutex_setprio(task_t *p, int prio);
+extern void rt_mutex_adjust_pi(task_t *p);
+#else
+static inline int rt_mutex_getprio(task_t *p)
+{
+       return p->normal_prio;
+}
+# define rt_mutex_adjust_pi(p)         do { } while (0)
+#endif
+
 extern void set_user_nice(task_t *p, long nice);
 extern int task_prio(const task_t *p);
 extern int task_nice(const task_t *p);
@@ -1408,6 +1452,11 @@ static inline void arch_pick_mmap_layout(struct mm_struct *mm)
 extern long sched_setaffinity(pid_t pid, cpumask_t new_mask);
 extern long sched_getaffinity(pid_t pid, cpumask_t *mask);
 
+#include <linux/sysdev.h>
+extern int sched_mc_power_savings, sched_smt_power_savings;
+extern struct sysdev_attribute attr_sched_mc_power_savings, attr_sched_smt_power_savings;
+extern int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls);
+
 extern void normalize_rt_tasks(void);
 
 #ifdef CONFIG_PM
index a22f9e173ad2d3b953dc3b90fb9df231b70557b2..693c0557e70bdf6b13baa898a4dca5c82b8ae919 100644 (file)
@@ -49,10 +49,3 @@ extern unsigned scx200_cb_base;
 #define SCx200_REV 0x3d                /* Revision Register */
 #define SCx200_CBA 0x3e                /* Configuration Base Address Register */
 #define SCx200_CBA_SCRATCH 0x64        /* Configuration Base Address Scratchpad */
-
-/*
-    Local variables:
-        compile-command: "make -C ../.. bzImage modules"
-        c-basic-offset: 8
-    End:
-*/
index 30cdd648ba79355d5dfed28fcbbb64ccf6be4de2..90dd069cc145c4b26a6fefe020aacee17d28aa65 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/spinlock.h>
 
-u32 scx200_gpio_configure(int index, u32 set, u32 clear);
+u32 scx200_gpio_configure(unsigned index, u32 set, u32 clear);
 
 extern unsigned scx200_gpio_base;
 extern long scx200_gpio_shadow[2];
@@ -17,7 +17,7 @@ extern long scx200_gpio_shadow[2];
 
 /* returns the value of the GPIO pin */
 
-static inline int scx200_gpio_get(int index) {
+static inline int scx200_gpio_get(unsigned index) {
        __SCx200_GPIO_BANK;
        __SCx200_GPIO_IOADDR + 0x04;
        __SCx200_GPIO_INDEX;
@@ -29,7 +29,7 @@ static inline int scx200_gpio_get(int index) {
    driven if the GPIO is configured as an output, it might not be the
    state of the GPIO right now if the GPIO is configured as an input) */
 
-static inline int scx200_gpio_current(int index) {
+static inline int scx200_gpio_current(unsigned index) {
         __SCx200_GPIO_BANK;
        __SCx200_GPIO_INDEX;
                
@@ -38,7 +38,7 @@ static inline int scx200_gpio_current(int index) {
 
 /* drive the GPIO signal high */
 
-static inline void scx200_gpio_set_high(int index) {
+static inline void scx200_gpio_set_high(unsigned index) {
        __SCx200_GPIO_BANK;
        __SCx200_GPIO_IOADDR;
        __SCx200_GPIO_SHADOW;
@@ -49,7 +49,7 @@ static inline void scx200_gpio_set_high(int index) {
 
 /* drive the GPIO signal low */
 
-static inline void scx200_gpio_set_low(int index) {
+static inline void scx200_gpio_set_low(unsigned index) {
        __SCx200_GPIO_BANK;
        __SCx200_GPIO_IOADDR;
        __SCx200_GPIO_SHADOW;
@@ -60,7 +60,7 @@ static inline void scx200_gpio_set_low(int index) {
 
 /* drive the GPIO signal to state */
 
-static inline void scx200_gpio_set(int index, int state) {
+static inline void scx200_gpio_set(unsigned index, int state) {
        __SCx200_GPIO_BANK;
        __SCx200_GPIO_IOADDR;
        __SCx200_GPIO_SHADOW;
@@ -73,7 +73,7 @@ static inline void scx200_gpio_set(int index, int state) {
 }
 
 /* toggle the GPIO signal */
-static inline void scx200_gpio_change(int index) {
+static inline void scx200_gpio_change(unsigned index) {
        __SCx200_GPIO_BANK;
        __SCx200_GPIO_IOADDR;
        __SCx200_GPIO_SHADOW;
@@ -87,10 +87,3 @@ static inline void scx200_gpio_change(int index) {
 #undef __SCx200_GPIO_SHADOW
 #undef __SCx200_GPIO_INDEX
 #undef __SCx200_GPIO_OUT
-
-/*
-    Local variables:
-        compile-command: "make -C ../.. bzImage modules"
-        c-basic-offset: 8
-    End:
-*/
index 951c4e858274618ba3295dbce522954088ea9379..fc1104a2cfa9c52841fe84ce7d3b68975df24c8b 100644 (file)
@@ -336,7 +336,6 @@ struct uart_driver {
        struct module           *owner;
        const char              *driver_name;
        const char              *dev_name;
-       const char              *devfs_name;
        int                      major;
        int                      minor;
        int                      nr;
index e928c0dcc29755d31c2ba5b7f1d96b1f3ac50b1e..c8bb68099eb9e35bf5ae2edba0c43244ca95ff5b 100644 (file)
@@ -642,10 +642,14 @@ struct spi_board_info {
        u16             bus_num;
        u16             chip_select;
 
+       /* mode becomes spi_device.mode, and is essential for chips
+        * where the default of SPI_CS_HIGH = 0 is wrong.
+        */
+       u8              mode;
+
        /* ... may need additional spi_device chip config data here.
         * avoid stuff protocol drivers can set; but include stuff
         * needed to behave without being bound to a driver:
-        *  - chipselect polarity
         *  - quirks like clock rate mattering when not selected
         */
 };
index dc3f3aa0c83e89ec345caac3d4af9fdb1eae35b1..c41e2d6d1acc3dfb4ca036a6a78047e02181d5c0 100644 (file)
@@ -199,6 +199,8 @@ static inline int zone_reclaim(struct zone *z, gfp_t mask, unsigned int order)
 }
 #endif
 
+extern int kswapd_run(int nid);
+
 #ifdef CONFIG_MMU
 /* linux/mm/shmem.c */
 extern int shmem_unuse(swp_entry_t entry, struct page *page);
index 33785b79d548a802e346022714d5032cacdbd097..008f04c5673715b33a52536e2bd4375bc064ff92 100644 (file)
@@ -174,9 +174,9 @@ asmlinkage long sys_waitid(int which, pid_t pid,
                           int options, struct rusage __user *ru);
 asmlinkage long sys_waitpid(pid_t pid, int __user *stat_addr, int options);
 asmlinkage long sys_set_tid_address(int __user *tidptr);
-asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
+asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
                        struct timespec __user *utime, u32 __user *uaddr2,
-                       int val3);
+                       u32 val3);
 
 asmlinkage long sys_init_module(void __user *umod, unsigned long len,
                                const char __user *uargs);
index 349ef908a2222d313ea7f87932a3a2d1d44b36b2..46e4d8f2771f9fa5812205c01a0fc85778fa9a44 100644 (file)
@@ -149,6 +149,7 @@ enum
        KERN_ACPI_VIDEO_FLAGS=71, /* int: flags for setting up video after ACPI sleep */
        KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */
        KERN_COMPAT_LOG=73,     /* int: print compat layer  messages */
+       KERN_MAX_LOCK_DEPTH=74,
 };
 
 
@@ -189,6 +190,7 @@ enum
        VM_ZONE_RECLAIM_MODE=31, /* reclaim local zone memory before going off node */
        VM_ZONE_RECLAIM_INTERVAL=32, /* time period to wait after reclaim failure */
        VM_PANIC_ON_OOM=33,     /* panic at out-of-memory */
+       VM_VDSO_ENABLED=34,     /* map VDSO into new processes? */
 };
 
 
index a305ae2e44b6dde305d3afe241768e32c47d8907..ec1eca85290ade96c5f42da4d74acac2a8ae2407 100644 (file)
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_NEWIDLE    \
                                | SD_BALANCE_EXEC       \
-                               | SD_WAKE_AFFINE,       \
+                               | SD_WAKE_AFFINE        \
+                               | BALANCE_FOR_POWER,    \
        .last_balance           = jiffies,              \
        .balance_interval       = 1,                    \
        .nr_balance_failed      = 0,                    \
index cb35ca50a0a66feffff3a63b598634efc9f1f027..b3b807e4b050031cf5a2e0e4dad2e1e4b31503a3 100644 (file)
@@ -57,7 +57,6 @@ struct tty_buffer {
        unsigned char *flag_buf_ptr;
        int used;
        int size;
-       int active;
        int commit;
        int read;
        /* Data points here */
@@ -259,7 +258,6 @@ struct tty_struct {
 #define TTY_DO_WRITE_WAKEUP    5       /* Call write_wakeup after queuing new */
 #define TTY_PUSH               6       /* n_tty private */
 #define TTY_CLOSING            7       /* ->close() in progress */
-#define TTY_DONT_FLIP          8       /* Defer buffer flip */
 #define TTY_LDISC              9       /* Line discipline attached */
 #define TTY_HW_COOK_OUT        14      /* Hardware can do output cooking */
 #define TTY_HW_COOK_IN                 15      /* Hardware can do input cooking */
index b368b296d035d1564f29586efb37365dac316ce3..58c961c9e1707027fe8989bfa821c78121fdb183 100644 (file)
@@ -157,7 +157,6 @@ struct tty_driver {
        struct cdev cdev;
        struct module   *owner;
        const char      *driver_name;
-       const char      *devfs_name;
        const char      *name;
        int     name_base;      /* offset of printed name */
        int     major;          /* major device number */
@@ -242,8 +241,15 @@ void tty_set_operations(struct tty_driver *driver, struct tty_operations *op);
  *     is also a promise, if the above case is true, not to signal
  *     overruns, either.)
  *
- * TTY_DRIVER_NO_DEVFS --- if set, do not create devfs entries. This
- *     is only used by tty_register_driver().
+ * TTY_DRIVER_DYNAMIC_DEV --- if set, the individual tty devices need
+ *     to be registered with a call to tty_register_driver() when the
+ *     device is found in the system and unregistered with a call to
+ *     tty_unregister_device() so the devices will be show up
+ *     properly in sysfs.  If not set, driver->num entries will be
+ *     created by the tty core in sysfs when tty_register_driver() is
+ *     called.  This is to be used by drivers that have tty devices
+ *     that can appear and disappear while the main tty driver is
+ *     registered with the tty core.
  *
  * TTY_DRIVER_DEVPTS_MEM -- don't use the standard arrays, instead
  *     use dynamic memory keyed through the devpts filesystem.  This
@@ -252,7 +258,7 @@ void tty_set_operations(struct tty_driver *driver, struct tty_operations *op);
 #define TTY_DRIVER_INSTALLED           0x0001
 #define TTY_DRIVER_RESET_TERMIOS       0x0002
 #define TTY_DRIVER_REAL_RAW            0x0004
-#define TTY_DRIVER_NO_DEVFS            0x0008
+#define TTY_DRIVER_DYNAMIC_DEV         0x0008
 #define TTY_DRIVER_DEVPTS_MEM          0x0010
 
 /* tty driver types */
index 31548303ee3767095f86efb47696ce433662450e..eb677cf56106cc17dfc1f05873c9478e93813935 100644 (file)
@@ -12,7 +12,7 @@ static inline int tty_insert_flip_char(struct tty_struct *tty,
                                        unsigned char ch, char flag)
 {
        struct tty_buffer *tb = tty->buf.tail;
-       if (tb && tb->active && tb->used < tb->size) {
+       if (tb && tb->used < tb->size) {
                tb->flag_buf_ptr[tb->used] = flag;
                tb->char_buf_ptr[tb->used++] = ch;
                return 1;
index a5e46e783ffa03ca4d38e918e09f4e8b78367380..3f235660a3cd6a76c4fa0480e649deaa5a4077d3 100644 (file)
@@ -177,8 +177,15 @@ typedef __u64 __bitwise __be64;
 
 #ifdef __KERNEL__
 typedef unsigned __bitwise__ gfp_t;
+
+#ifdef CONFIG_RESOURCES_64BIT
+typedef u64 resource_size_t;
+#else
+typedef u32 resource_size_t;
 #endif
 
+#endif /* __KERNEL__ */
+
 struct ustat {
        __kernel_daddr_t        f_tfree;
        __kernel_ino_t          f_tinode;
index 914f911325be9483cc29ab481f3014e0e27df879..e39b7cc433902565d9b7aa5d450f5be86a10118b 100644 (file)
@@ -966,7 +966,7 @@ extern void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
 extern struct inode_operations ufs_file_inode_operations;
 extern const struct file_operations ufs_file_operations;
 
-extern struct address_space_operations ufs_aops;
+extern const struct address_space_operations ufs_aops;
 
 /* ialloc.c */
 extern void ufs_free_inode (struct inode *inode);
index 1192ed8f4fe8ae965ccca10ce7ca745e0440b61d..011bcfeb9f090a7a49dbf54c4819d3306160c852 100644 (file)
@@ -28,6 +28,9 @@ struct watchdog_info {
 #define        WDIOC_KEEPALIVE         _IOR(WATCHDOG_IOCTL_BASE, 5, int)
 #define        WDIOC_SETTIMEOUT        _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
 #define        WDIOC_GETTIMEOUT        _IOR(WATCHDOG_IOCTL_BASE, 7, int)
+#define        WDIOC_SETPRETIMEOUT     _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
+#define        WDIOC_GETPRETIMEOUT     _IOR(WATCHDOG_IOCTL_BASE, 9, int)
+#define        WDIOC_GETTIMELEFT       _IOR(WATCHDOG_IOCTL_BASE, 10, int)
 
 #define        WDIOF_UNKNOWN           -1      /* Unknown flag error */
 #define        WDIOS_UNKNOWN           -1      /* Unknown status error */
@@ -38,9 +41,10 @@ struct watchdog_info {
 #define        WDIOF_EXTERN2           0x0008  /* External relay 2 */
 #define        WDIOF_POWERUNDER        0x0010  /* Power bad/power fault */
 #define        WDIOF_CARDRESET         0x0020  /* Card previously reset the CPU */
-#define WDIOF_POWEROVER                0x0040  /* Power over voltage */
-#define WDIOF_SETTIMEOUT       0x0080  /* Set timeout (in seconds) */
-#define WDIOF_MAGICCLOSE       0x0100  /* Supports magic close char */
+#define        WDIOF_POWEROVER         0x0040  /* Power over voltage */
+#define        WDIOF_SETTIMEOUT        0x0080  /* Set timeout (in seconds) */
+#define        WDIOF_MAGICCLOSE        0x0100  /* Supports magic close char */
+#define        WDIOF_PRETIMEOUT        0x0200  /* Pretimeout (in seconds), get/set */
 #define        WDIOF_KEEPALIVEPING     0x8000  /* Keep alive ping reply */
 
 #define        WDIOS_DISABLECARD       0x0001  /* Turn off the watchdog timer */
index 074c4008ad5296fa5f73c5c21e67dd3d42fd69d2..d91d88f93c8b3485e36f3c5bda8ed8dab31b905c 100644 (file)
@@ -89,9 +89,9 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
                struct v4l2_queryctrl *qctrl);
 const char **cx2341x_ctrl_get_menu(u32 id);
 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
-               struct v4l2_ext_controls *ctrls, int cmd);
+               struct v4l2_ext_controls *ctrls, unsigned int cmd);
 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p);
-void cx2341x_log_status(struct cx2341x_mpeg_params *p, int cardid);
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix);
 
 /* Firmware names */
 #define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw"
index a1b473190e650b6ca2db5be2375facb3bde7c42c..62dae1a8c4412c3f363193ad8efdd898f3fd0c22 100644 (file)
@@ -314,7 +314,6 @@ void *priv;
        /* for videodev.c intenal usage -- please don't touch */
        int users;                     /* video_exclusive_{open|close} ... */
        struct mutex lock;             /* ... helper function uses these   */
-       char devfs_name[64];           /* devfs */
        struct class_device class_dev; /* sysfs */
 };
 
index 446afc3ea27fab8b506e7f2c274311ecc0bd6c67..758f8bf133c7c8f5553e302f55ca804fc89d985a 100644 (file)
 
 /* specific - Analog Devices */
 #define AC97_AD_TEST           0x5a    /* test register */
+#define AC97_AD_TEST2          0x5c    /* undocumented test register 2 */
 #define AC97_AD_CODEC_CFG      0x70    /* codec configuration */
 #define AC97_AD_JACK_SPDIF     0x72    /* Jack Sense & S/PDIF */
 #define AC97_AD_SERIAL_CFG     0x74    /* Serial Configuration */
index 3bf5911fe8273570206983931f22f0a118d05cb2..3d98884920261483c00f47879432933be112583f 100644 (file)
@@ -32,8 +32,8 @@ struct snd_akm4xxx;
 struct snd_ak4xxx_ops {
        void (*lock)(struct snd_akm4xxx *ak, int chip);
        void (*unlock)(struct snd_akm4xxx *ak, int chip);
-       void (*write)(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsigned char val);
-       // unsigned char (*read)(struct snd_akm4xxx *ak, int chip, unsigned char reg);
+       void (*write)(struct snd_akm4xxx *ak, int chip, unsigned char reg,
+                     unsigned char val);
        void (*set_rate_val)(struct snd_akm4xxx *ak, unsigned int rate);
 };
 
@@ -41,29 +41,40 @@ struct snd_ak4xxx_ops {
 
 struct snd_akm4xxx {
        struct snd_card *card;
-       unsigned int num_adcs;                          /* AK4524 or AK4528 ADCs */
-       unsigned int num_dacs;                          /* AK4524 or AK4528 DACs */
-       unsigned char images[AK4XXX_IMAGE_SIZE];        /* saved register image */
-       unsigned char ipga_gain[AK4XXX_MAX_CHIPS][2];   /* saved register image for IPGA (AK4528) */
+       unsigned int num_adcs;                  /* AK4524 or AK4528 ADCs */
+       unsigned int num_dacs;                  /* AK4524 or AK4528 DACs */
+       unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */
+       unsigned char ipga_gain[AK4XXX_MAX_CHIPS][2]; /* saved register image
+                                                      * for IPGA (AK4528)
+                                                      */
        unsigned long private_value[AK4XXX_MAX_CHIPS];  /* helper for driver */
        void *private_data[AK4XXX_MAX_CHIPS];           /* helper for driver */
        /* template should fill the following fields */
-       unsigned int idx_offset;                        /* control index offset */
+       unsigned int idx_offset;                /* control index offset */
        enum {
                SND_AK4524, SND_AK4528, SND_AK4529,
                SND_AK4355, SND_AK4358, SND_AK4381
        } type;
+       unsigned int *num_stereo;       /* array of combined counts
+                                        * for the mixer
+                                        */
+       char **channel_names;           /* array of mixer channel names */
        struct snd_ak4xxx_ops ops;
 };
 
-void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsigned char val);
+void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
+                      unsigned char val);
 void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state);
 void snd_akm4xxx_init(struct snd_akm4xxx *ak);
 int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak);
 
-#define snd_akm4xxx_get(ak,chip,reg) (ak)->images[(chip) * 16 + (reg)]
-#define snd_akm4xxx_set(ak,chip,reg,val) ((ak)->images[(chip) * 16 + (reg)] = (val))
-#define snd_akm4xxx_get_ipga(ak,chip,reg) (ak)->ipga_gain[chip][(reg)-4]
-#define snd_akm4xxx_set_ipga(ak,chip,reg,val) ((ak)->ipga_gain[chip][(reg)-4] = (val))
+#define snd_akm4xxx_get(ak,chip,reg) \
+       (ak)->images[(chip) * 16 + (reg)]
+#define snd_akm4xxx_set(ak,chip,reg,val) \
+       ((ak)->images[(chip) * 16 + (reg)] = (val))
+#define snd_akm4xxx_get_ipga(ak,chip,reg) \
+       (ak)->ipga_gain[chip][(reg)-4]
+#define snd_akm4xxx_set_ipga(ak,chip,reg,val) \
+       ((ak)->ipga_gain[chip][(reg)-4] = (val))
 
 #endif /* __SOUND_AK4XXX_ADDA_H */
index d29e3d31d149eb7f2c46946046c8279e8a7914b8..d45170b9e0b70add3d0b7483a2341477036a9ac6 100644 (file)
@@ -62,7 +62,8 @@ static int snd_legacy_find_free_irq(int *irq_table)
 {
        while (*irq_table != -1) {
                if (!request_irq(*irq_table, snd_legacy_empty_irq_handler,
-                                SA_INTERRUPT, "ALSA Test IRQ", (void *) irq_table)) {
+                                SA_INTERRUPT | SA_PROBEIRQ, "ALSA Test IRQ",
+                                (void *) irq_table)) {
                        free_irq(*irq_table, (void *) irq_table);
                        return *irq_table;
                }
index df55b36656010b726aeb8b7a3e08984e2940a8da..f70f2fd273c2152708bdac6800d038229b58a8cc 100644 (file)
@@ -339,9 +339,14 @@ config BASE_FULL
          kernel data structures. This saves memory on small machines,
          but may reduce performance.
 
+config RT_MUTEXES
+       boolean
+       select PLIST
+
 config FUTEX
        bool "Enable futex support" if EMBEDDED
        default y
+       select RT_MUTEXES
        help
          Disabling this option will cause the kernel to be built without
          support for "fast userspace mutexes".  The resulting kernel may not
index a2300078f2b7d98f97a603678e40a39d034bdea5..633a268d270d3cc8bfa906c1a22476caa9645360 100644 (file)
@@ -6,7 +6,6 @@ obj-y                           := main.o version.o mounts.o initramfs.o
 obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
 
 mounts-y                       := do_mounts.o
-mounts-$(CONFIG_DEVFS_FS)      += do_mounts_devfs.o
 mounts-$(CONFIG_BLK_DEV_RAM)   += do_mounts_rd.o
 mounts-$(CONFIG_BLK_DEV_INITRD)        += do_mounts_initrd.o
 mounts-$(CONFIG_BLK_DEV_MD)    += do_mounts_md.o
index 21b3b8f33a728c505cd7396d9e7517775c07706c..94aeec7aa917fbf727e5be22c55f842621b31ef3 100644 (file)
@@ -325,7 +325,7 @@ static int __init mount_nfs_root(void)
 {
        void *data = nfs_root_data();
 
-       create_dev("/dev/root", ROOT_DEV, NULL);
+       create_dev("/dev/root", ROOT_DEV);
        if (data &&
            do_mount_root("/dev/root", "nfs", root_mountflags, data) == 0)
                return 1;
@@ -386,7 +386,7 @@ void __init mount_root(void)
                        change_floppy("root floppy");
        }
 #endif
-       create_dev("/dev/root", ROOT_DEV, root_device_name);
+       create_dev("/dev/root", ROOT_DEV);
        mount_block_root("/dev/root", root_mountflags);
 }
 
@@ -397,8 +397,6 @@ void __init prepare_namespace(void)
 {
        int is_floppy;
 
-       mount_devfs();
-
        if (root_delay) {
                printk(KERN_INFO "Waiting %dsec before mounting root device...\n",
                       root_delay);
@@ -428,10 +426,8 @@ void __init prepare_namespace(void)
 
        mount_root();
 out:
-       umount_devfs("/dev");
        sys_mount(".", "/", NULL, MS_MOVE, NULL);
        sys_chroot(".");
        security_sb_post_mountroot();
-       mount_devfs_fs ();
 }
 
index e0a7ac9649e1e4c10c080a7691744ce62e6bc497..e7f2e7fa066eb6715c0f54fb27649338b60f475a 100644 (file)
@@ -1,6 +1,5 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/init.h>
 #include <linux/syscalls.h>
 #include <linux/unistd.h>
@@ -15,25 +14,12 @@ void  mount_root(void);
 extern int root_mountflags;
 extern char *root_device_name;
 
-#ifdef CONFIG_DEVFS_FS
-
-void mount_devfs(void);
-void umount_devfs(char *path);
-int  create_dev(char *name, dev_t dev, char *devfs_name);
-
-#else
-
-static inline void mount_devfs(void) {}
-static inline void umount_devfs(const char *path) {}
-
-static inline int create_dev(char *name, dev_t dev, char *devfs_name)
+static inline int create_dev(char *name, dev_t dev)
 {
        sys_unlink(name);
        return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev));
 }
 
-#endif
-
 #if BITS_PER_LONG == 32
 static inline u32 bstat(char *name)
 {
diff --git a/init/do_mounts_devfs.c b/init/do_mounts_devfs.c
deleted file mode 100644 (file)
index cc52647..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-
-#include <linux/kernel.h>
-#include <linux/dirent.h>
-#include <linux/string.h>
-
-#include "do_mounts.h"
-
-void __init mount_devfs(void)
-{
-       sys_mount("devfs", "/dev", "devfs", 0, NULL);
-}
-
-void __init umount_devfs(char *path)
-{
-       sys_umount(path, 0);
-}
-
-/*
- * If the dir will fit in *buf, return its length.  If it won't fit, return
- * zero.  Return -ve on error.
- */
-static int __init do_read_dir(int fd, void *buf, int len)
-{
-       long bytes, n;
-       char *p = buf;
-       sys_lseek(fd, 0, 0);
-
-       for (bytes = 0; bytes < len; bytes += n) {
-               n = sys_getdents64(fd, (struct linux_dirent64 *)(p + bytes),
-                                       len - bytes);
-               if (n < 0)
-                       return n;
-               if (n == 0)
-                       return bytes;
-       }
-       return 0;
-}
-
-/*
- * Try to read all of a directory.  Returns the contents at *p, which
- * is kmalloced memory.  Returns the number of bytes read at *len.  Returns
- * NULL on error.
- */
-static void * __init read_dir(char *path, int *len)
-{
-       int size;
-       int fd = sys_open(path, 0, 0);
-
-       *len = 0;
-       if (fd < 0)
-               return NULL;
-
-       for (size = 1 << 9; size <= (PAGE_SIZE << MAX_ORDER); size <<= 1) {
-               void *p = kmalloc(size, GFP_KERNEL);
-               int n;
-               if (!p)
-                       break;
-               n = do_read_dir(fd, p, size);
-               if (n > 0) {
-                       sys_close(fd);
-                       *len = n;
-                       return p;
-               }
-               kfree(p);
-               if (n == -EINVAL)
-                       continue;       /* Try a larger buffer */
-               if (n < 0)
-                       break;
-       }
-       sys_close(fd);
-       return NULL;
-}
-
-/*
- * recursively scan <path>, looking for a device node of type <dev>
- */
-static int __init find_in_devfs(char *path, unsigned dev)
-{
-       char *end = path + strlen(path);
-       int rest = path + 64 - end;
-       int size;
-       char *p = read_dir(path, &size);
-       char *s;
-
-       if (!p)
-               return -1;
-       for (s = p; s < p + size; s += ((struct linux_dirent64 *)s)->d_reclen) {
-               struct linux_dirent64 *d = (struct linux_dirent64 *)s;
-               if (strlen(d->d_name) + 2 > rest)
-                       continue;
-               switch (d->d_type) {
-                       case DT_BLK:
-                               sprintf(end, "/%s", d->d_name);
-                               if (bstat(path) != dev)
-                                       break;
-                               kfree(p);
-                               return 0;
-                       case DT_DIR:
-                               if (strcmp(d->d_name, ".") == 0)
-                                       break;
-                               if (strcmp(d->d_name, "..") == 0)
-                                       break;
-                               sprintf(end, "/%s", d->d_name);
-                               if (find_in_devfs(path, dev) < 0)
-                                       break;
-                               kfree(p);
-                               return 0;
-               }
-       }
-       kfree(p);
-       return -1;
-}
-
-/*
- * create a device node called <name> which points to
- * <devfs_name> if possible, otherwise find a device node
- * which matches <dev> and make <name> a symlink pointing to it.
- */
-int __init create_dev(char *name, dev_t dev, char *devfs_name)
-{
-       char path[64];
-
-       sys_unlink(name);
-       if (devfs_name && devfs_name[0]) {
-               if (strncmp(devfs_name, "/dev/", 5) == 0)
-                       devfs_name += 5;
-               sprintf(path, "/dev/%s", devfs_name);
-               if (sys_access(path, 0) == 0)
-                       return sys_symlink(devfs_name, name);
-       }
-       if (!dev)
-               return -1;
-       strcpy(path, "/dev");
-       if (find_in_devfs(path, new_encode_dev(dev)) < 0)
-               return -1;
-       return sys_symlink(path + 5, name);
-}
index 405f9031af873c1d4631e597e65f123d2fe95e65..a06f037fa000a932d9de7b6f8dee909e5ce01720 100644 (file)
@@ -44,7 +44,7 @@ static void __init handle_initrd(void)
        int pid;
 
        real_root_dev = new_encode_dev(ROOT_DEV);
-       create_dev("/dev/root.old", Root_RAM0, NULL);
+       create_dev("/dev/root.old", Root_RAM0);
        /* mount initrd on rootfs' /root */
        mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
        sys_mkdir("/old", 0700);
@@ -54,7 +54,6 @@ static void __init handle_initrd(void)
        sys_chdir("/root");
        sys_mount(".", "/", NULL, MS_MOVE, NULL);
        sys_chroot(".");
-       mount_devfs_fs ();
 
        current->flags |= PF_NOFREEZE;
        pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
@@ -71,7 +70,6 @@ static void __init handle_initrd(void)
        sys_chroot(".");
        sys_close(old_fd);
        sys_close(root_fd);
-       umount_devfs("/old/dev");
 
        if (new_decode_dev(real_root_dev) == Root_RAM0) {
                sys_chdir("/old");
@@ -107,7 +105,7 @@ static void __init handle_initrd(void)
 int __init initrd_load(void)
 {
        if (mount_initrd) {
-               create_dev("/dev/ram", Root_RAM0, NULL);
+               create_dev("/dev/ram", Root_RAM0);
                /*
                 * Load the initrd data into /dev/ram0. Execute it as initrd
                 * unless /dev/ram0 is supposed to be our actual root device,
index f6f36806f84a09bed0f76467a3133a08a84e01ac..2429e1bf8c60a1277edaed473760cfad8e486a1f 100644 (file)
@@ -125,19 +125,18 @@ static void __init md_setup_drive(void)
                int err = 0;
                char *devname;
                mdu_disk_info_t dinfo;
-               char name[16], devfs_name[16];
+               char name[16];
 
                minor = md_setup_args[ent].minor;
                partitioned = md_setup_args[ent].partitioned;
                devname = md_setup_args[ent].device_names;
 
                sprintf(name, "/dev/md%s%d", partitioned?"_d":"", minor);
-               sprintf(devfs_name, "/dev/md/%s%d", partitioned?"d":"", minor);
                if (partitioned)
                        dev = MKDEV(mdp_major, minor << MdpMinorShift);
                else
                        dev = MKDEV(MD_MAJOR, minor);
-               create_dev(name, dev, devfs_name);
+               create_dev(name, dev);
                for (i = 0; i < MD_SB_DISKS && devname != 0; i++) {
                        char *p;
                        char comp_name[64];
@@ -272,7 +271,7 @@ __setup("md=", md_setup);
 
 void __init md_run_setup(void)
 {
-       create_dev("/dev/md0", MKDEV(MD_MAJOR, 0), "md/0");
+       create_dev("/dev/md0", MKDEV(MD_MAJOR, 0));
        if (raid_noautodetect)
                printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n");
        else {
index c2683fcd792deb75a5f79d3e0ec02424fecd1a7c..ed652f40f075a68e2b41b68911a97a0f5224ed96 100644 (file)
@@ -262,8 +262,8 @@ int __init rd_load_disk(int n)
 {
        if (rd_prompt)
                change_floppy("root floppy disk to be loaded into RAM disk");
-       create_dev("/dev/root", ROOT_DEV, root_device_name);
-       create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n), NULL);
+       create_dev("/dev/root", ROOT_DEV);
+       create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n));
        return rd_load_image("/dev/root");
 }
 
index 80af1a52485fcfd5b272e747d7a1576b0993167f..bce0eb7f4f8fb50413a516b1a3bafbb8ae81b821 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/kernel.h>
 #include <linux/syscalls.h>
 #include <linux/string.h>
@@ -48,6 +47,7 @@
 #include <linux/mempolicy.h>
 #include <linux/key.h>
 #include <linux/unwind.h>
+#include <linux/buffer_head.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -80,7 +80,6 @@ extern void mca_init(void);
 extern void sbus_init(void);
 extern void sysctl_init(void);
 extern void signals_init(void);
-extern void buffer_init(void);
 extern void pidhash_init(void);
 extern void pidmap_init(void);
 extern void prio_tree_init(void);
index 752bd7d383af34ecf7f72b3472d4fa9ccbd9a519..82fb182f6f618421cb822aac8131914486b8a651 100644 (file)
@@ -16,6 +16,9 @@ obj-$(CONFIG_FUTEX) += futex.o
 ifeq ($(CONFIG_COMPAT),y)
 obj-$(CONFIG_FUTEX) += futex_compat.o
 endif
+obj-$(CONFIG_RT_MUTEXES) += rtmutex.o
+obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o
+obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o spinlock.o
 obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
index 368c4f03fe0e9fd0b7426b650d83a847badb05d7..126ca43d5d2ba9eb566af4380668c9546266efcd 100644 (file)
@@ -521,6 +521,7 @@ static void do_acct_process(struct file *file)
 
 /**
  * acct_init_pacct - initialize a new pacct_struct
+ * @pacct: per-process accounting info struct to initialize
  */
 void acct_init_pacct(struct pacct_struct *pacct)
 {
@@ -576,7 +577,7 @@ void acct_collect(long exitcode, int group_dead)
  *
  * handles process accounting for an exiting task
  */
-void acct_process()
+void acct_process(void)
 {
        struct file *file = NULL;
 
index 7dfac7031bd734f6c117e66b660b436b842e41be..82443fb433efcb9d550126be82dabf80c0308c23 100644 (file)
@@ -818,7 +818,7 @@ err:
  */
 unsigned int audit_serial(void)
 {
-       static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
+       static DEFINE_SPINLOCK(serial_lock);
        static unsigned int serial = 0;
 
        unsigned long flags;
index 9ebd96fda2958835a7d0d0aa6dc1993ee11f1098..dc5e3f01efe747c9d1816895ae1a1e40fb527489 100644 (file)
@@ -658,8 +658,7 @@ static void audit_log_task_context(struct audit_buffer *ab)
        return;
 
 error_path:
-       if (ctx)
-               kfree(ctx);
+       kfree(ctx);
        audit_panic("error in audit_log_task_context");
        return;
 }
@@ -1367,7 +1366,7 @@ int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr)
  * @mqdes: MQ descriptor
  * @msg_len: Message length
  * @msg_prio: Message priority
- * @abs_timeout: Message timeout in absolute time
+ * @u_abs_timeout: Message timeout in absolute time
  *
  * Returns 0 for success or NULL context or < 0 on error.
  */
@@ -1409,8 +1408,8 @@ int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio,
  * __audit_mq_timedreceive - record audit data for a POSIX MQ timed receive
  * @mqdes: MQ descriptor
  * @msg_len: Message length
- * @msg_prio: Message priority
- * @abs_timeout: Message timeout in absolute time
+ * @u_msg_prio: Message priority
+ * @u_abs_timeout: Message timeout in absolute time
  *
  * Returns 0 for success or NULL context or < 0 on error.
  */
@@ -1558,7 +1557,6 @@ int __audit_ipc_obj(struct kern_ipc_perm *ipcp)
  * @uid: msgq user id
  * @gid: msgq group id
  * @mode: msgq mode (permissions)
- * @ipcp: in-kernel IPC permissions
  *
  * Returns 0 for success or NULL context or < 0 on error.
  */
index 03dcd981846a6b8020a07c058312c7277621be49..70fbf2e83766abb527d84bc6c4ddc30646036609 100644 (file)
@@ -18,7 +18,7 @@
 /* This protects CPUs going up and down... */
 static DEFINE_MUTEX(cpucontrol);
 
-static BLOCKING_NOTIFIER_HEAD(cpu_chain);
+static __cpuinitdata BLOCKING_NOTIFIER_HEAD(cpu_chain);
 
 #ifdef CONFIG_HOTPLUG_CPU
 static struct task_struct *lock_cpu_hotplug_owner;
@@ -69,10 +69,13 @@ EXPORT_SYMBOL_GPL(lock_cpu_hotplug_interruptible);
 #endif /* CONFIG_HOTPLUG_CPU */
 
 /* Need to know about CPUs going up/down? */
-int register_cpu_notifier(struct notifier_block *nb)
+int __cpuinit register_cpu_notifier(struct notifier_block *nb)
 {
        return blocking_notifier_chain_register(&cpu_chain, nb);
 }
+
+#ifdef CONFIG_HOTPLUG_CPU
+
 EXPORT_SYMBOL(register_cpu_notifier);
 
 void unregister_cpu_notifier(struct notifier_block *nb)
@@ -81,7 +84,6 @@ void unregister_cpu_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL(unregister_cpu_notifier);
 
-#ifdef CONFIG_HOTPLUG_CPU
 static inline void check_for_tasks(int cpu)
 {
        struct task_struct *p;
index 304ef637be6c700e7b5d73172222a0e05e5f96d8..ab06b9f88f64677ca036dea0285f740ccb54e1e9 100644 (file)
@@ -925,10 +925,19 @@ fastcall NORET_TYPE void do_exit(long code)
        mpol_free(tsk->mempolicy);
        tsk->mempolicy = NULL;
 #endif
+       /*
+        * This must happen late, after the PID is not
+        * hashed anymore:
+        */
+       if (unlikely(!list_empty(&tsk->pi_state_list)))
+               exit_pi_state_list(tsk);
+       if (unlikely(current->pi_state_cache))
+               kfree(current->pi_state_cache);
        /*
         * If DEBUG_MUTEXES is on, make sure we are holding no locks:
         */
        mutex_debug_check_no_locks_held(tsk);
+       rt_mutex_debug_check_no_locks_held(tsk);
 
        if (tsk->io_context)
                exit_io_context();
index 9b4e54ef0225e21f92366302ae9430933b330dbd..628198a4f28a722b25b37c26ecbd401c67919a8d 100644 (file)
@@ -104,6 +104,7 @@ static kmem_cache_t *mm_cachep;
 void free_task(struct task_struct *tsk)
 {
        free_thread_info(tsk->thread_info);
+       rt_mutex_debug_task_free(tsk);
        free_task_struct(tsk);
 }
 EXPORT_SYMBOL(free_task);
@@ -913,6 +914,19 @@ asmlinkage long sys_set_tid_address(int __user *tidptr)
        return current->pid;
 }
 
+static inline void rt_mutex_init_task(struct task_struct *p)
+{
+#ifdef CONFIG_RT_MUTEXES
+       spin_lock_init(&p->pi_lock);
+       plist_head_init(&p->pi_waiters, &p->pi_lock);
+       p->pi_blocked_on = NULL;
+# ifdef CONFIG_DEBUG_RT_MUTEXES
+       spin_lock_init(&p->held_list_lock);
+       INIT_LIST_HEAD(&p->held_list_head);
+# endif
+#endif
+}
+
 /*
  * This creates a new process as a copy of the old one,
  * but does not actually start it yet.
@@ -1034,6 +1048,8 @@ static task_t *copy_process(unsigned long clone_flags,
        mpol_fix_fork_child_flag(p);
 #endif
 
+       rt_mutex_init_task(p);
+
 #ifdef CONFIG_DEBUG_MUTEXES
        p->blocked_on = NULL; /* not blocked yet */
 #endif
@@ -1076,6 +1092,9 @@ static task_t *copy_process(unsigned long clone_flags,
 #ifdef CONFIG_COMPAT
        p->compat_robust_list = NULL;
 #endif
+       INIT_LIST_HEAD(&p->pi_state_list);
+       p->pi_state_cache = NULL;
+
        /*
         * sigaltstack should be cleared when sharing the same VM
         */
index e1a380c77a5a2ac947f4fceee190fa7518488f41..6c91f938005db0719bac62a643fff9b411b7f594 100644 (file)
  *  (C) Copyright 2006 Red Hat Inc, All Rights Reserved
  *  Thanks to Thomas Gleixner for suggestions, analysis and fixes.
  *
+ *  PI-futex support started by Ingo Molnar and Thomas Gleixner
+ *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
  *  Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly
  *  enough at me, Linus for the original (flawed) idea, Matthew
  *  Kirkwood for proof-of-concept implementation.
@@ -46,6 +50,8 @@
 #include <linux/signal.h>
 #include <asm/futex.h>
 
+#include "rtmutex_common.h"
+
 #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
 
 /*
@@ -63,7 +69,7 @@ union futex_key {
                int offset;
        } shared;
        struct {
-               unsigned long uaddr;
+               unsigned long address;
                struct mm_struct *mm;
                int offset;
        } private;
@@ -74,6 +80,27 @@ union futex_key {
        } both;
 };
 
+/*
+ * Priority Inheritance state:
+ */
+struct futex_pi_state {
+       /*
+        * list of 'owned' pi_state instances - these have to be
+        * cleaned up in do_exit() if the task exits prematurely:
+        */
+       struct list_head list;
+
+       /*
+        * The PI object:
+        */
+       struct rt_mutex pi_mutex;
+
+       struct task_struct *owner;
+       atomic_t refcount;
+
+       union futex_key key;
+};
+
 /*
  * We use this hashed waitqueue instead of a normal wait_queue_t, so
  * we can wake only the relevant ones (hashed queues may be shared).
@@ -87,15 +114,19 @@ struct futex_q {
        struct list_head list;
        wait_queue_head_t waiters;
 
-       /* Which hash list lock to use. */
+       /* Which hash list lock to use: */
        spinlock_t *lock_ptr;
 
-       /* Key which the futex is hashed on. */
+       /* Key which the futex is hashed on: */
        union futex_key key;
 
-       /* For fd, sigio sent using these. */
+       /* For fd, sigio sent using these: */
        int fd;
        struct file *filp;
+
+       /* Optional priority inheritance state: */
+       struct futex_pi_state *pi_state;
+       struct task_struct *task;
 };
 
 /*
@@ -144,8 +175,9 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2)
  *
  * Should be called with &current->mm->mmap_sem but NOT any spinlocks.
  */
-static int get_futex_key(unsigned long uaddr, union futex_key *key)
+static int get_futex_key(u32 __user *uaddr, union futex_key *key)
 {
+       unsigned long address = (unsigned long)uaddr;
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        struct page *page;
@@ -154,16 +186,16 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
        /*
         * The futex address must be "naturally" aligned.
         */
-       key->both.offset = uaddr % PAGE_SIZE;
+       key->both.offset = address % PAGE_SIZE;
        if (unlikely((key->both.offset % sizeof(u32)) != 0))
                return -EINVAL;
-       uaddr -= key->both.offset;
+       address -= key->both.offset;
 
        /*
         * The futex is hashed differently depending on whether
         * it's in a shared or private mapping.  So check vma first.
         */
-       vma = find_extend_vma(mm, uaddr);
+       vma = find_extend_vma(mm, address);
        if (unlikely(!vma))
                return -EFAULT;
 
@@ -184,7 +216,7 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
         */
        if (likely(!(vma->vm_flags & VM_MAYSHARE))) {
                key->private.mm = mm;
-               key->private.uaddr = uaddr;
+               key->private.address = address;
                return 0;
        }
 
@@ -194,7 +226,7 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
        key->shared.inode = vma->vm_file->f_dentry->d_inode;
        key->both.offset++; /* Bit 0 of offset indicates inode-based key. */
        if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
-               key->shared.pgoff = (((uaddr - vma->vm_start) >> PAGE_SHIFT)
+               key->shared.pgoff = (((address - vma->vm_start) >> PAGE_SHIFT)
                                     + vma->vm_pgoff);
                return 0;
        }
@@ -205,7 +237,7 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
         * from swap.  But that's a lot of code to duplicate here
         * for a rare case, so we simply fetch the page.
         */
-       err = get_user_pages(current, mm, uaddr, 1, 0, 0, &page, NULL);
+       err = get_user_pages(current, mm, address, 1, 0, 0, &page, NULL);
        if (err >= 0) {
                key->shared.pgoff =
                        page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
@@ -246,17 +278,243 @@ static void drop_key_refs(union futex_key *key)
        }
 }
 
-static inline int get_futex_value_locked(int *dest, int __user *from)
+static inline int get_futex_value_locked(u32 *dest, u32 __user *from)
 {
        int ret;
 
        inc_preempt_count();
-       ret = __copy_from_user_inatomic(dest, from, sizeof(int));
+       ret = __copy_from_user_inatomic(dest, from, sizeof(u32));
        dec_preempt_count();
 
        return ret ? -EFAULT : 0;
 }
 
+/*
+ * Fault handling. Called with current->mm->mmap_sem held.
+ */
+static int futex_handle_fault(unsigned long address, int attempt)
+{
+       struct vm_area_struct * vma;
+       struct mm_struct *mm = current->mm;
+
+       if (attempt >= 2 || !(vma = find_vma(mm, address)) ||
+           vma->vm_start > address || !(vma->vm_flags & VM_WRITE))
+               return -EFAULT;
+
+       switch (handle_mm_fault(mm, vma, address, 1)) {
+       case VM_FAULT_MINOR:
+               current->min_flt++;
+               break;
+       case VM_FAULT_MAJOR:
+               current->maj_flt++;
+               break;
+       default:
+               return -EFAULT;
+       }
+       return 0;
+}
+
+/*
+ * PI code:
+ */
+static int refill_pi_state_cache(void)
+{
+       struct futex_pi_state *pi_state;
+
+       if (likely(current->pi_state_cache))
+               return 0;
+
+       pi_state = kmalloc(sizeof(*pi_state), GFP_KERNEL);
+
+       if (!pi_state)
+               return -ENOMEM;
+
+       memset(pi_state, 0, sizeof(*pi_state));
+       INIT_LIST_HEAD(&pi_state->list);
+       /* pi_mutex gets initialized later */
+       pi_state->owner = NULL;
+       atomic_set(&pi_state->refcount, 1);
+
+       current->pi_state_cache = pi_state;
+
+       return 0;
+}
+
+static struct futex_pi_state * alloc_pi_state(void)
+{
+       struct futex_pi_state *pi_state = current->pi_state_cache;
+
+       WARN_ON(!pi_state);
+       current->pi_state_cache = NULL;
+
+       return pi_state;
+}
+
+static void free_pi_state(struct futex_pi_state *pi_state)
+{
+       if (!atomic_dec_and_test(&pi_state->refcount))
+               return;
+
+       /*
+        * If pi_state->owner is NULL, the owner is most probably dying
+        * and has cleaned up the pi_state already
+        */
+       if (pi_state->owner) {
+               spin_lock_irq(&pi_state->owner->pi_lock);
+               list_del_init(&pi_state->list);
+               spin_unlock_irq(&pi_state->owner->pi_lock);
+
+               rt_mutex_proxy_unlock(&pi_state->pi_mutex, pi_state->owner);
+       }
+
+       if (current->pi_state_cache)
+               kfree(pi_state);
+       else {
+               /*
+                * pi_state->list is already empty.
+                * clear pi_state->owner.
+                * refcount is at 0 - put it back to 1.
+                */
+               pi_state->owner = NULL;
+               atomic_set(&pi_state->refcount, 1);
+               current->pi_state_cache = pi_state;
+       }
+}
+
+/*
+ * Look up the task based on what TID userspace gave us.
+ * We dont trust it.
+ */
+static struct task_struct * futex_find_get_task(pid_t pid)
+{
+       struct task_struct *p;
+
+       read_lock(&tasklist_lock);
+       p = find_task_by_pid(pid);
+       if (!p)
+               goto out_unlock;
+       if ((current->euid != p->euid) && (current->euid != p->uid)) {
+               p = NULL;
+               goto out_unlock;
+       }
+       if (p->state == EXIT_ZOMBIE || p->exit_state == EXIT_ZOMBIE) {
+               p = NULL;
+               goto out_unlock;
+       }
+       get_task_struct(p);
+out_unlock:
+       read_unlock(&tasklist_lock);
+
+       return p;
+}
+
+/*
+ * This task is holding PI mutexes at exit time => bad.
+ * Kernel cleans up PI-state, but userspace is likely hosed.
+ * (Robust-futex cleanup is separate and might save the day for userspace.)
+ */
+void exit_pi_state_list(struct task_struct *curr)
+{
+       struct futex_hash_bucket *hb;
+       struct list_head *next, *head = &curr->pi_state_list;
+       struct futex_pi_state *pi_state;
+       union futex_key key;
+
+       /*
+        * We are a ZOMBIE and nobody can enqueue itself on
+        * pi_state_list anymore, but we have to be careful
+        * versus waiters unqueueing themselfs
+        */
+       spin_lock_irq(&curr->pi_lock);
+       while (!list_empty(head)) {
+
+               next = head->next;
+               pi_state = list_entry(next, struct futex_pi_state, list);
+               key = pi_state->key;
+               spin_unlock_irq(&curr->pi_lock);
+
+               hb = hash_futex(&key);
+               spin_lock(&hb->lock);
+
+               spin_lock_irq(&curr->pi_lock);
+               if (head->next != next) {
+                       spin_unlock(&hb->lock);
+                       continue;
+               }
+
+               list_del_init(&pi_state->list);
+
+               WARN_ON(pi_state->owner != curr);
+
+               pi_state->owner = NULL;
+               spin_unlock_irq(&curr->pi_lock);
+
+               rt_mutex_unlock(&pi_state->pi_mutex);
+
+               spin_unlock(&hb->lock);
+
+               spin_lock_irq(&curr->pi_lock);
+       }
+       spin_unlock_irq(&curr->pi_lock);
+}
+
+static int
+lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
+{
+       struct futex_pi_state *pi_state = NULL;
+       struct futex_q *this, *next;
+       struct list_head *head;
+       struct task_struct *p;
+       pid_t pid;
+
+       head = &hb->chain;
+
+       list_for_each_entry_safe(this, next, head, list) {
+               if (match_futex (&this->key, &me->key)) {
+                       /*
+                        * Another waiter already exists - bump up
+                        * the refcount and return its pi_state:
+                        */
+                       pi_state = this->pi_state;
+                       atomic_inc(&pi_state->refcount);
+                       me->pi_state = pi_state;
+
+                       return 0;
+               }
+       }
+
+       /*
+        * We are the first waiter - try to look up the real owner and
+        * attach the new pi_state to it:
+        */
+       pid = uval & FUTEX_TID_MASK;
+       p = futex_find_get_task(pid);
+       if (!p)
+               return -ESRCH;
+
+       pi_state = alloc_pi_state();
+
+       /*
+        * Initialize the pi_mutex in locked state and make 'p'
+        * the owner of it:
+        */
+       rt_mutex_init_proxy_locked(&pi_state->pi_mutex, p);
+
+       /* Store the key for possible exit cleanups: */
+       pi_state->key = me->key;
+
+       spin_lock_irq(&p->pi_lock);
+       list_add(&pi_state->list, &p->pi_state_list);
+       pi_state->owner = p;
+       spin_unlock_irq(&p->pi_lock);
+
+       put_task_struct(p);
+
+       me->pi_state = pi_state;
+
+       return 0;
+}
+
 /*
  * The hash bucket lock must be held when this is called.
  * Afterwards, the futex_q must not be accessed.
@@ -284,16 +542,80 @@ static void wake_futex(struct futex_q *q)
        q->lock_ptr = NULL;
 }
 
+static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
+{
+       struct task_struct *new_owner;
+       struct futex_pi_state *pi_state = this->pi_state;
+       u32 curval, newval;
+
+       if (!pi_state)
+               return -EINVAL;
+
+       new_owner = rt_mutex_next_owner(&pi_state->pi_mutex);
+
+       /*
+        * This happens when we have stolen the lock and the original
+        * pending owner did not enqueue itself back on the rt_mutex.
+        * Thats not a tragedy. We know that way, that a lock waiter
+        * is on the fly. We make the futex_q waiter the pending owner.
+        */
+       if (!new_owner)
+               new_owner = this->task;
+
+       /*
+        * We pass it to the next owner. (The WAITERS bit is always
+        * kept enabled while there is PI state around. We must also
+        * preserve the owner died bit.)
+        */
+       newval = (uval & FUTEX_OWNER_DIED) | FUTEX_WAITERS | new_owner->pid;
+
+       inc_preempt_count();
+       curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+       dec_preempt_count();
+
+       if (curval == -EFAULT)
+               return -EFAULT;
+       if (curval != uval)
+               return -EINVAL;
+
+       list_del_init(&pi_state->owner->pi_state_list);
+       list_add(&pi_state->list, &new_owner->pi_state_list);
+       pi_state->owner = new_owner;
+       rt_mutex_unlock(&pi_state->pi_mutex);
+
+       return 0;
+}
+
+static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
+{
+       u32 oldval;
+
+       /*
+        * There is no waiter, so we unlock the futex. The owner died
+        * bit has not to be preserved here. We are the owner:
+        */
+       inc_preempt_count();
+       oldval = futex_atomic_cmpxchg_inatomic(uaddr, uval, 0);
+       dec_preempt_count();
+
+       if (oldval == -EFAULT)
+               return oldval;
+       if (oldval != uval)
+               return -EAGAIN;
+
+       return 0;
+}
+
 /*
  * Wake up all waiters hashed on the physical page that is mapped
  * to this virtual address:
  */
-static int futex_wake(unsigned long uaddr, int nr_wake)
+static int futex_wake(u32 __user *uaddr, int nr_wake)
 {
-       union futex_key key;
-       struct futex_hash_bucket *bh;
-       struct list_head *head;
+       struct futex_hash_bucket *hb;
        struct futex_q *this, *next;
+       struct list_head *head;
+       union futex_key key;
        int ret;
 
        down_read(&current->mm->mmap_sem);
@@ -302,19 +624,21 @@ static int futex_wake(unsigned long uaddr, int nr_wake)
        if (unlikely(ret != 0))
                goto out;
 
-       bh = hash_futex(&key);
-       spin_lock(&bh->lock);
-       head = &bh->chain;
+       hb = hash_futex(&key);
+       spin_lock(&hb->lock);
+       head = &hb->chain;
 
        list_for_each_entry_safe(this, next, head, list) {
                if (match_futex (&this->key, &key)) {
+                       if (this->pi_state)
+                               return -EINVAL;
                        wake_futex(this);
                        if (++ret >= nr_wake)
                                break;
                }
        }
 
-       spin_unlock(&bh->lock);
+       spin_unlock(&hb->lock);
 out:
        up_read(&current->mm->mmap_sem);
        return ret;
@@ -324,10 +648,12 @@ out:
  * Wake up all waiters hashed on the physical page that is mapped
  * to this virtual address:
  */
-static int futex_wake_op(unsigned long uaddr1, unsigned long uaddr2, int nr_wake, int nr_wake2, int op)
+static int
+futex_wake_op(u32 __user *uaddr1, u32 __user *uaddr2,
+             int nr_wake, int nr_wake2, int op)
 {
        union futex_key key1, key2;
-       struct futex_hash_bucket *bh1, *bh2;
+       struct futex_hash_bucket *hb1, *hb2;
        struct list_head *head;
        struct futex_q *this, *next;
        int ret, op_ret, attempt = 0;
@@ -342,27 +668,29 @@ retryfull:
        if (unlikely(ret != 0))
                goto out;
 
-       bh1 = hash_futex(&key1);
-       bh2 = hash_futex(&key2);
+       hb1 = hash_futex(&key1);
+       hb2 = hash_futex(&key2);
 
 retry:
-       if (bh1 < bh2)
-               spin_lock(&bh1->lock);
-       spin_lock(&bh2->lock);
-       if (bh1 > bh2)
-               spin_lock(&bh1->lock);
+       if (hb1 < hb2)
+               spin_lock(&hb1->lock);
+       spin_lock(&hb2->lock);
+       if (hb1 > hb2)
+               spin_lock(&hb1->lock);
 
-       op_ret = futex_atomic_op_inuser(op, (int __user *)uaddr2);
+       op_ret = futex_atomic_op_inuser(op, uaddr2);
        if (unlikely(op_ret < 0)) {
-               int dummy;
+               u32 dummy;
 
-               spin_unlock(&bh1->lock);
-               if (bh1 != bh2)
-                       spin_unlock(&bh2->lock);
+               spin_unlock(&hb1->lock);
+               if (hb1 != hb2)
+                       spin_unlock(&hb2->lock);
 
 #ifndef CONFIG_MMU
-               /* we don't get EFAULT from MMU faults if we don't have an MMU,
-                * but we might get them from range checking */
+               /*
+                * we don't get EFAULT from MMU faults if we don't have an MMU,
+                * but we might get them from range checking
+                */
                ret = op_ret;
                goto out;
 #endif
@@ -372,47 +700,34 @@ retry:
                        goto out;
                }
 
-               /* futex_atomic_op_inuser needs to both read and write
+               /*
+                * futex_atomic_op_inuser needs to both read and write
                 * *(int __user *)uaddr2, but we can't modify it
                 * non-atomically.  Therefore, if get_user below is not
                 * enough, we need to handle the fault ourselves, while
-                * still holding the mmap_sem.  */
+                * still holding the mmap_sem.
+                */
                if (attempt++) {
-                       struct vm_area_struct * vma;
-                       struct mm_struct *mm = current->mm;
-
-                       ret = -EFAULT;
-                       if (attempt >= 2 ||
-                           !(vma = find_vma(mm, uaddr2)) ||
-                           vma->vm_start > uaddr2 ||
-                           !(vma->vm_flags & VM_WRITE))
-                               goto out;
-
-                       switch (handle_mm_fault(mm, vma, uaddr2, 1)) {
-                       case VM_FAULT_MINOR:
-                               current->min_flt++;
-                               break;
-                       case VM_FAULT_MAJOR:
-                               current->maj_flt++;
-                               break;
-                       default:
+                       if (futex_handle_fault((unsigned long)uaddr2,
+                                              attempt))
                                goto out;
-                       }
                        goto retry;
                }
 
-               /* If we would have faulted, release mmap_sem,
-                * fault it in and start all over again.  */
+               /*
+                * If we would have faulted, release mmap_sem,
+                * fault it in and start all over again.
+                */
                up_read(&current->mm->mmap_sem);
 
-               ret = get_user(dummy, (int __user *)uaddr2);
+               ret = get_user(dummy, uaddr2);
                if (ret)
                        return ret;
 
                goto retryfull;
        }
 
-       head = &bh1->chain;
+       head = &hb1->chain;
 
        list_for_each_entry_safe(this, next, head, list) {
                if (match_futex (&this->key, &key1)) {
@@ -423,7 +738,7 @@ retry:
        }
 
        if (op_ret > 0) {
-               head = &bh2->chain;
+               head = &hb2->chain;
 
                op_ret = 0;
                list_for_each_entry_safe(this, next, head, list) {
@@ -436,9 +751,9 @@ retry:
                ret += op_ret;
        }
 
-       spin_unlock(&bh1->lock);
-       if (bh1 != bh2)
-               spin_unlock(&bh2->lock);
+       spin_unlock(&hb1->lock);
+       if (hb1 != hb2)
+               spin_unlock(&hb2->lock);
 out:
        up_read(&current->mm->mmap_sem);
        return ret;
@@ -448,11 +763,11 @@ out:
  * Requeue all waiters hashed on one physical page to another
  * physical page.
  */
-static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
-                        int nr_wake, int nr_requeue, int *valp)
+static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
+                        int nr_wake, int nr_requeue, u32 *cmpval)
 {
        union futex_key key1, key2;
-       struct futex_hash_bucket *bh1, *bh2;
+       struct futex_hash_bucket *hb1, *hb2;
        struct list_head *head1;
        struct futex_q *this, *next;
        int ret, drop_count = 0;
@@ -467,68 +782,72 @@ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
        if (unlikely(ret != 0))
                goto out;
 
-       bh1 = hash_futex(&key1);
-       bh2 = hash_futex(&key2);
+       hb1 = hash_futex(&key1);
+       hb2 = hash_futex(&key2);
 
-       if (bh1 < bh2)
-               spin_lock(&bh1->lock);
-       spin_lock(&bh2->lock);
-       if (bh1 > bh2)
-               spin_lock(&bh1->lock);
+       if (hb1 < hb2)
+               spin_lock(&hb1->lock);
+       spin_lock(&hb2->lock);
+       if (hb1 > hb2)
+               spin_lock(&hb1->lock);
 
-       if (likely(valp != NULL)) {
-               int curval;
+       if (likely(cmpval != NULL)) {
+               u32 curval;
 
-               ret = get_futex_value_locked(&curval, (int __user *)uaddr1);
+               ret = get_futex_value_locked(&curval, uaddr1);
 
                if (unlikely(ret)) {
-                       spin_unlock(&bh1->lock);
-                       if (bh1 != bh2)
-                               spin_unlock(&bh2->lock);
+                       spin_unlock(&hb1->lock);
+                       if (hb1 != hb2)
+                               spin_unlock(&hb2->lock);
 
-                       /* If we would have faulted, release mmap_sem, fault
+                       /*
+                        * If we would have faulted, release mmap_sem, fault
                         * it in and start all over again.
                         */
                        up_read(&current->mm->mmap_sem);
 
-                       ret = get_user(curval, (int __user *)uaddr1);
+                       ret = get_user(curval, uaddr1);
 
                        if (!ret)
                                goto retry;
 
                        return ret;
                }
-               if (curval != *valp) {
+               if (curval != *cmpval) {
                        ret = -EAGAIN;
                        goto out_unlock;
                }
        }
 
-       head1 = &bh1->chain;
+       head1 = &hb1->chain;
        list_for_each_entry_safe(this, next, head1, list) {
                if (!match_futex (&this->key, &key1))
                        continue;
                if (++ret <= nr_wake) {
                        wake_futex(this);
                } else {
-                       list_move_tail(&this->list, &bh2->chain);
-                       this->lock_ptr = &bh2->lock;
+                       /*
+                        * If key1 and key2 hash to the same bucket, no need to
+                        * requeue.
+                        */
+                       if (likely(head1 != &hb2->chain)) {
+                               list_move_tail(&this->list, &hb2->chain);
+                               this->lock_ptr = &hb2->lock;
+                       }
                        this->key = key2;
                        get_key_refs(&key2);
                        drop_count++;
 
                        if (ret - nr_wake >= nr_requeue)
                                break;
-                       /* Make sure to stop if key1 == key2 */
-                       if (head1 == &bh2->chain && head1 != &next->list)
-                               head1 = &this->list;
                }
        }
 
 out_unlock:
-       spin_unlock(&bh1->lock);
-       if (bh1 != bh2)
-               spin_unlock(&bh2->lock);
+       spin_unlock(&hb1->lock);
+       if (hb1 != hb2)
+               spin_unlock(&hb2->lock);
 
        /* drop_key_refs() must be called outside the spinlocks. */
        while (--drop_count >= 0)
@@ -543,7 +862,7 @@ out:
 static inline struct futex_hash_bucket *
 queue_lock(struct futex_q *q, int fd, struct file *filp)
 {
-       struct futex_hash_bucket *bh;
+       struct futex_hash_bucket *hb;
 
        q->fd = fd;
        q->filp = filp;
@@ -551,23 +870,24 @@ queue_lock(struct futex_q *q, int fd, struct file *filp)
        init_waitqueue_head(&q->waiters);
 
        get_key_refs(&q->key);
-       bh = hash_futex(&q->key);
-       q->lock_ptr = &bh->lock;
+       hb = hash_futex(&q->key);
+       q->lock_ptr = &hb->lock;
 
-       spin_lock(&bh->lock);
-       return bh;
+       spin_lock(&hb->lock);
+       return hb;
 }
 
-static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *bh)
+static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
 {
-       list_add_tail(&q->list, &bh->chain);
-       spin_unlock(&bh->lock);
+       list_add_tail(&q->list, &hb->chain);
+       q->task = current;
+       spin_unlock(&hb->lock);
 }
 
 static inline void
-queue_unlock(struct futex_q *q, struct futex_hash_bucket *bh)
+queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb)
 {
-       spin_unlock(&bh->lock);
+       spin_unlock(&hb->lock);
        drop_key_refs(&q->key);
 }
 
@@ -579,16 +899,17 @@ queue_unlock(struct futex_q *q, struct futex_hash_bucket *bh)
 /* The key must be already stored in q->key. */
 static void queue_me(struct futex_q *q, int fd, struct file *filp)
 {
-       struct futex_hash_bucket *bh;
-       bh = queue_lock(q, fd, filp);
-       __queue_me(q, bh);
+       struct futex_hash_bucket *hb;
+
+       hb = queue_lock(q, fd, filp);
+       __queue_me(q, hb);
 }
 
 /* Return 1 if we were still queued (ie. 0 means we were woken) */
 static int unqueue_me(struct futex_q *q)
 {
-       int ret = 0;
        spinlock_t *lock_ptr;
+       int ret = 0;
 
        /* In the common case we don't take the spinlock, which is nice. */
  retry:
@@ -614,6 +935,9 @@ static int unqueue_me(struct futex_q *q)
                }
                WARN_ON(list_empty(&q->list));
                list_del(&q->list);
+
+               BUG_ON(q->pi_state);
+
                spin_unlock(lock_ptr);
                ret = 1;
        }
@@ -622,21 +946,42 @@ static int unqueue_me(struct futex_q *q)
        return ret;
 }
 
-static int futex_wait(unsigned long uaddr, int val, unsigned long time)
+/*
+ * PI futexes can not be requeued and must remove themself from the
+ * hash bucket. The hash bucket lock is held on entry and dropped here.
+ */
+static void unqueue_me_pi(struct futex_q *q, struct futex_hash_bucket *hb)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int ret, curval;
+       WARN_ON(list_empty(&q->list));
+       list_del(&q->list);
+
+       BUG_ON(!q->pi_state);
+       free_pi_state(q->pi_state);
+       q->pi_state = NULL;
+
+       spin_unlock(&hb->lock);
+
+       drop_key_refs(&q->key);
+}
+
+static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
+{
+       struct task_struct *curr = current;
+       DECLARE_WAITQUEUE(wait, curr);
+       struct futex_hash_bucket *hb;
        struct futex_q q;
-       struct futex_hash_bucket *bh;
+       u32 uval;
+       int ret;
 
+       q.pi_state = NULL;
  retry:
-       down_read(&current->mm->mmap_sem);
+       down_read(&curr->mm->mmap_sem);
 
        ret = get_futex_key(uaddr, &q.key);
        if (unlikely(ret != 0))
                goto out_release_sem;
 
-       bh = queue_lock(&q, -1, NULL);
+       hb = queue_lock(&q, -1, NULL);
 
        /*
         * Access the page AFTER the futex is queued.
@@ -658,37 +1003,35 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
         * We hold the mmap semaphore, so the mapping cannot have changed
         * since we looked it up in get_futex_key.
         */
-
-       ret = get_futex_value_locked(&curval, (int __user *)uaddr);
+       ret = get_futex_value_locked(&uval, uaddr);
 
        if (unlikely(ret)) {
-               queue_unlock(&q, bh);
+               queue_unlock(&q, hb);
 
-               /* If we would have faulted, release mmap_sem, fault it in and
+               /*
+                * If we would have faulted, release mmap_sem, fault it in and
                 * start all over again.
                 */
-               up_read(&current->mm->mmap_sem);
+               up_read(&curr->mm->mmap_sem);
 
-               ret = get_user(curval, (int __user *)uaddr);
+               ret = get_user(uval, uaddr);
 
                if (!ret)
                        goto retry;
                return ret;
        }
-       if (curval != val) {
-               ret = -EWOULDBLOCK;
-               queue_unlock(&q, bh);
-               goto out_release_sem;
-       }
+       ret = -EWOULDBLOCK;
+       if (uval != val)
+               goto out_unlock_release_sem;
 
        /* Only actually queue if *uaddr contained val.  */
-       __queue_me(&q, bh);
+       __queue_me(&q, hb);
 
        /*
         * Now the futex is queued and we have checked the data, we
         * don't want to hold mmap_sem while we sleep.
-        */     
-       up_read(&current->mm->mmap_sem);
+        */
+       up_read(&curr->mm->mmap_sem);
 
        /*
         * There might have been scheduling since the queue_me(), as we
@@ -720,12 +1063,421 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
                return 0;
        if (time == 0)
                return -ETIMEDOUT;
-       /* We expect signal_pending(current), but another thread may
-        * have handled it for us already. */
+       /*
+        * We expect signal_pending(current), but another thread may
+        * have handled it for us already.
+        */
        return -EINTR;
 
+ out_unlock_release_sem:
+       queue_unlock(&q, hb);
+
  out_release_sem:
+       up_read(&curr->mm->mmap_sem);
+       return ret;
+}
+
+/*
+ * Userspace tried a 0 -> TID atomic transition of the futex value
+ * and failed. The kernel side here does the whole locking operation:
+ * if there are waiters then it will block, it does PI, etc. (Due to
+ * races the kernel might see a 0 value of the futex too.)
+ */
+static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock,
+                           struct hrtimer_sleeper *to)
+{
+       struct task_struct *curr = current;
+       struct futex_hash_bucket *hb;
+       u32 uval, newval, curval;
+       struct futex_q q;
+       int ret, attempt = 0;
+
+       if (refill_pi_state_cache())
+               return -ENOMEM;
+
+       q.pi_state = NULL;
+ retry:
+       down_read(&curr->mm->mmap_sem);
+
+       ret = get_futex_key(uaddr, &q.key);
+       if (unlikely(ret != 0))
+               goto out_release_sem;
+
+       hb = queue_lock(&q, -1, NULL);
+
+ retry_locked:
+       /*
+        * To avoid races, we attempt to take the lock here again
+        * (by doing a 0 -> TID atomic cmpxchg), while holding all
+        * the locks. It will most likely not succeed.
+        */
+       newval = current->pid;
+
+       inc_preempt_count();
+       curval = futex_atomic_cmpxchg_inatomic(uaddr, 0, newval);
+       dec_preempt_count();
+
+       if (unlikely(curval == -EFAULT))
+               goto uaddr_faulted;
+
+       /* We own the lock already */
+       if (unlikely((curval & FUTEX_TID_MASK) == current->pid)) {
+               if (!detect && 0)
+                       force_sig(SIGKILL, current);
+               ret = -EDEADLK;
+               goto out_unlock_release_sem;
+       }
+
+       /*
+        * Surprise - we got the lock. Just return
+        * to userspace:
+        */
+       if (unlikely(!curval))
+               goto out_unlock_release_sem;
+
+       uval = curval;
+       newval = uval | FUTEX_WAITERS;
+
+       inc_preempt_count();
+       curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+       dec_preempt_count();
+
+       if (unlikely(curval == -EFAULT))
+               goto uaddr_faulted;
+       if (unlikely(curval != uval))
+               goto retry_locked;
+
+       /*
+        * We dont have the lock. Look up the PI state (or create it if
+        * we are the first waiter):
+        */
+       ret = lookup_pi_state(uval, hb, &q);
+
+       if (unlikely(ret)) {
+               /*
+                * There were no waiters and the owner task lookup
+                * failed. When the OWNER_DIED bit is set, then we
+                * know that this is a robust futex and we actually
+                * take the lock. This is safe as we are protected by
+                * the hash bucket lock. We also set the waiters bit
+                * unconditionally here, to simplify glibc handling of
+                * multiple tasks racing to acquire the lock and
+                * cleanup the problems which were left by the dead
+                * owner.
+                */
+               if (curval & FUTEX_OWNER_DIED) {
+                       uval = newval;
+                       newval = current->pid |
+                               FUTEX_OWNER_DIED | FUTEX_WAITERS;
+
+                       inc_preempt_count();
+                       curval = futex_atomic_cmpxchg_inatomic(uaddr,
+                                                              uval, newval);
+                       dec_preempt_count();
+
+                       if (unlikely(curval == -EFAULT))
+                               goto uaddr_faulted;
+                       if (unlikely(curval != uval))
+                               goto retry_locked;
+                       ret = 0;
+               }
+               goto out_unlock_release_sem;
+       }
+
+       /*
+        * Only actually queue now that the atomic ops are done:
+        */
+       __queue_me(&q, hb);
+
+       /*
+        * Now the futex is queued and we have checked the data, we
+        * don't want to hold mmap_sem while we sleep.
+        */
+       up_read(&curr->mm->mmap_sem);
+
+       WARN_ON(!q.pi_state);
+       /*
+        * Block on the PI mutex:
+        */
+       if (!trylock)
+               ret = rt_mutex_timed_lock(&q.pi_state->pi_mutex, to, 1);
+       else {
+               ret = rt_mutex_trylock(&q.pi_state->pi_mutex);
+               /* Fixup the trylock return value: */
+               ret = ret ? 0 : -EWOULDBLOCK;
+       }
+
+       down_read(&curr->mm->mmap_sem);
+       hb = queue_lock(&q, -1, NULL);
+
+       /*
+        * Got the lock. We might not be the anticipated owner if we
+        * did a lock-steal - fix up the PI-state in that case.
+        */
+       if (!ret && q.pi_state->owner != curr) {
+               u32 newtid = current->pid | FUTEX_WAITERS;
+
+               /* Owner died? */
+               if (q.pi_state->owner != NULL) {
+                       spin_lock_irq(&q.pi_state->owner->pi_lock);
+                       list_del_init(&q.pi_state->list);
+                       spin_unlock_irq(&q.pi_state->owner->pi_lock);
+               } else
+                       newtid |= FUTEX_OWNER_DIED;
+
+               q.pi_state->owner = current;
+
+               spin_lock_irq(&current->pi_lock);
+               list_add(&q.pi_state->list, &current->pi_state_list);
+               spin_unlock_irq(&current->pi_lock);
+
+               /* Unqueue and drop the lock */
+               unqueue_me_pi(&q, hb);
+               up_read(&curr->mm->mmap_sem);
+               /*
+                * We own it, so we have to replace the pending owner
+                * TID. This must be atomic as we have preserve the
+                * owner died bit here.
+                */
+               ret = get_user(uval, uaddr);
+               while (!ret) {
+                       newval = (uval & FUTEX_OWNER_DIED) | newtid;
+                       curval = futex_atomic_cmpxchg_inatomic(uaddr,
+                                                              uval, newval);
+                       if (curval == -EFAULT)
+                               ret = -EFAULT;
+                       if (curval == uval)
+                               break;
+                       uval = curval;
+               }
+       } else {
+               /*
+                * Catch the rare case, where the lock was released
+                * when we were on the way back before we locked
+                * the hash bucket.
+                */
+               if (ret && q.pi_state->owner == curr) {
+                       if (rt_mutex_trylock(&q.pi_state->pi_mutex))
+                               ret = 0;
+               }
+               /* Unqueue and drop the lock */
+               unqueue_me_pi(&q, hb);
+               up_read(&curr->mm->mmap_sem);
+       }
+
+       if (!detect && ret == -EDEADLK && 0)
+               force_sig(SIGKILL, current);
+
+       return ret;
+
+ out_unlock_release_sem:
+       queue_unlock(&q, hb);
+
+ out_release_sem:
+       up_read(&curr->mm->mmap_sem);
+       return ret;
+
+ uaddr_faulted:
+       /*
+        * We have to r/w  *(int __user *)uaddr, but we can't modify it
+        * non-atomically.  Therefore, if get_user below is not
+        * enough, we need to handle the fault ourselves, while
+        * still holding the mmap_sem.
+        */
+       if (attempt++) {
+               if (futex_handle_fault((unsigned long)uaddr, attempt))
+                       goto out_unlock_release_sem;
+
+               goto retry_locked;
+       }
+
+       queue_unlock(&q, hb);
+       up_read(&curr->mm->mmap_sem);
+
+       ret = get_user(uval, uaddr);
+       if (!ret && (uval != -EFAULT))
+               goto retry;
+
+       return ret;
+}
+
+/*
+ * Restart handler
+ */
+static long futex_lock_pi_restart(struct restart_block *restart)
+{
+       struct hrtimer_sleeper timeout, *to = NULL;
+       int ret;
+
+       restart->fn = do_no_restart_syscall;
+
+       if (restart->arg2 || restart->arg3) {
+               to = &timeout;
+               hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS);
+               hrtimer_init_sleeper(to, current);
+               to->timer.expires.tv64 = ((u64)restart->arg1 << 32) |
+                       (u64) restart->arg0;
+       }
+
+       pr_debug("lock_pi restart: %p, %d (%d)\n",
+                (u32 __user *)restart->arg0, current->pid);
+
+       ret = do_futex_lock_pi((u32 __user *)restart->arg0, restart->arg1,
+                              0, to);
+
+       if (ret != -EINTR)
+               return ret;
+
+       restart->fn = futex_lock_pi_restart;
+
+       /* The other values are filled in */
+       return -ERESTART_RESTARTBLOCK;
+}
+
+/*
+ * Called from the syscall entry below.
+ */
+static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
+                        long nsec, int trylock)
+{
+       struct hrtimer_sleeper timeout, *to = NULL;
+       struct restart_block *restart;
+       int ret;
+
+       if (sec != MAX_SCHEDULE_TIMEOUT) {
+               to = &timeout;
+               hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS);
+               hrtimer_init_sleeper(to, current);
+               to->timer.expires = ktime_set(sec, nsec);
+       }
+
+       ret = do_futex_lock_pi(uaddr, detect, trylock, to);
+
+       if (ret != -EINTR)
+               return ret;
+
+       pr_debug("lock_pi interrupted: %p, %d (%d)\n", uaddr, current->pid);
+
+       restart = &current_thread_info()->restart_block;
+       restart->fn = futex_lock_pi_restart;
+       restart->arg0 = (unsigned long) uaddr;
+       restart->arg1 = detect;
+       if (to) {
+               restart->arg2 = to->timer.expires.tv64 & 0xFFFFFFFF;
+               restart->arg3 = to->timer.expires.tv64 >> 32;
+       } else
+               restart->arg2 = restart->arg3 = 0;
+
+       return -ERESTART_RESTARTBLOCK;
+}
+
+/*
+ * Userspace attempted a TID -> 0 atomic transition, and failed.
+ * This is the in-kernel slowpath: we look up the PI state (if any),
+ * and do the rt-mutex unlock.
+ */
+static int futex_unlock_pi(u32 __user *uaddr)
+{
+       struct futex_hash_bucket *hb;
+       struct futex_q *this, *next;
+       u32 uval;
+       struct list_head *head;
+       union futex_key key;
+       int ret, attempt = 0;
+
+retry:
+       if (get_user(uval, uaddr))
+               return -EFAULT;
+       /*
+        * We release only a lock we actually own:
+        */
+       if ((uval & FUTEX_TID_MASK) != current->pid)
+               return -EPERM;
+       /*
+        * First take all the futex related locks:
+        */
+       down_read(&current->mm->mmap_sem);
+
+       ret = get_futex_key(uaddr, &key);
+       if (unlikely(ret != 0))
+               goto out;
+
+       hb = hash_futex(&key);
+       spin_lock(&hb->lock);
+
+retry_locked:
+       /*
+        * To avoid races, try to do the TID -> 0 atomic transition
+        * again. If it succeeds then we can return without waking
+        * anyone else up:
+        */
+       inc_preempt_count();
+       uval = futex_atomic_cmpxchg_inatomic(uaddr, current->pid, 0);
+       dec_preempt_count();
+
+       if (unlikely(uval == -EFAULT))
+               goto pi_faulted;
+       /*
+        * Rare case: we managed to release the lock atomically,
+        * no need to wake anyone else up:
+        */
+       if (unlikely(uval == current->pid))
+               goto out_unlock;
+
+       /*
+        * Ok, other tasks may need to be woken up - check waiters
+        * and do the wakeup if necessary:
+        */
+       head = &hb->chain;
+
+       list_for_each_entry_safe(this, next, head, list) {
+               if (!match_futex (&this->key, &key))
+                       continue;
+               ret = wake_futex_pi(uaddr, uval, this);
+               /*
+                * The atomic access to the futex value
+                * generated a pagefault, so retry the
+                * user-access and the wakeup:
+                */
+               if (ret == -EFAULT)
+                       goto pi_faulted;
+               goto out_unlock;
+       }
+       /*
+        * No waiters - kernel unlocks the futex:
+        */
+       ret = unlock_futex_pi(uaddr, uval);
+       if (ret == -EFAULT)
+               goto pi_faulted;
+
+out_unlock:
+       spin_unlock(&hb->lock);
+out:
        up_read(&current->mm->mmap_sem);
+
+       return ret;
+
+pi_faulted:
+       /*
+        * We have to r/w  *(int __user *)uaddr, but we can't modify it
+        * non-atomically.  Therefore, if get_user below is not
+        * enough, we need to handle the fault ourselves, while
+        * still holding the mmap_sem.
+        */
+       if (attempt++) {
+               if (futex_handle_fault((unsigned long)uaddr, attempt))
+                       goto out_unlock;
+
+               goto retry_locked;
+       }
+
+       spin_unlock(&hb->lock);
+       up_read(&current->mm->mmap_sem);
+
+       ret = get_user(uval, uaddr);
+       if (!ret && (uval != -EFAULT))
+               goto retry;
+
        return ret;
 }
 
@@ -735,6 +1487,7 @@ static int futex_close(struct inode *inode, struct file *filp)
 
        unqueue_me(q);
        kfree(q);
+
        return 0;
 }
 
@@ -766,7 +1519,7 @@ static struct file_operations futex_fops = {
  * Signal allows caller to avoid the race which would occur if they
  * set the sigio stuff up afterwards.
  */
-static int futex_fd(unsigned long uaddr, int signal)
+static int futex_fd(u32 __user *uaddr, int signal)
 {
        struct futex_q *q;
        struct file *filp;
@@ -803,6 +1556,7 @@ static int futex_fd(unsigned long uaddr, int signal)
                err = -ENOMEM;
                goto error;
        }
+       q->pi_state = NULL;
 
        down_read(&current->mm->mmap_sem);
        err = get_futex_key(uaddr, &q->key);
@@ -840,7 +1594,7 @@ error:
  * Implementation: user-space maintains a per-thread list of locks it
  * is holding. Upon do_exit(), the kernel carefully walks this list,
  * and marks all locks that are owned by this thread with the
- * FUTEX_OWNER_DEAD bit, and wakes up a waiter (if any). The list is
+ * FUTEX_OWNER_DIED bit, and wakes up a waiter (if any). The list is
  * always manipulated with the lock held, so the list is private and
  * per-thread. Userspace also maintains a per-thread 'list_op_pending'
  * field, to allow the kernel to clean up if the thread dies after
@@ -915,7 +1669,7 @@ err_unlock:
  */
 int handle_futex_death(u32 __user *uaddr, struct task_struct *curr)
 {
-       u32 uval;
+       u32 uval, nval;
 
 retry:
        if (get_user(uval, uaddr))
@@ -932,12 +1686,16 @@ retry:
                 * thread-death.) The rest of the cleanup is done in
                 * userspace.
                 */
-               if (futex_atomic_cmpxchg_inatomic(uaddr, uval,
-                                        uval | FUTEX_OWNER_DIED) != uval)
+               nval = futex_atomic_cmpxchg_inatomic(uaddr, uval,
+                                                    uval | FUTEX_OWNER_DIED);
+               if (nval == -EFAULT)
+                       return -1;
+
+               if (nval != uval)
                        goto retry;
 
                if (uval & FUTEX_WAITERS)
-                       futex_wake((unsigned long)uaddr, 1);
+                       futex_wake(uaddr, 1);
        }
        return 0;
 }
@@ -978,7 +1736,7 @@ void exit_robust_list(struct task_struct *curr)
        while (entry != &head->list) {
                /*
                 * A pending lock might already be on the list, so
-                * dont process it twice:
+                * don't process it twice:
                 */
                if (entry != pending)
                        if (handle_futex_death((void *)entry + futex_offset,
@@ -999,8 +1757,8 @@ void exit_robust_list(struct task_struct *curr)
        }
 }
 
-long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
-               unsigned long uaddr2, int val2, int val3)
+long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
+               u32 __user *uaddr2, u32 val2, u32 val3)
 {
        int ret;
 
@@ -1024,6 +1782,15 @@ long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
        case FUTEX_WAKE_OP:
                ret = futex_wake_op(uaddr, uaddr2, val, val2, val3);
                break;
+       case FUTEX_LOCK_PI:
+               ret = futex_lock_pi(uaddr, val, timeout, val2, 0);
+               break;
+       case FUTEX_UNLOCK_PI:
+               ret = futex_unlock_pi(uaddr);
+               break;
+       case FUTEX_TRYLOCK_PI:
+               ret = futex_lock_pi(uaddr, 0, timeout, val2, 1);
+               break;
        default:
                ret = -ENOSYS;
        }
@@ -1031,29 +1798,33 @@ long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout,
 }
 
 
-asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
+asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
                          struct timespec __user *utime, u32 __user *uaddr2,
-                         int val3)
+                         u32 val3)
 {
        struct timespec t;
        unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
-       int val2 = 0;
+       u32 val2 = 0;
 
-       if (utime && (op == FUTEX_WAIT)) {
+       if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
                if (copy_from_user(&t, utime, sizeof(t)) != 0)
                        return -EFAULT;
                if (!timespec_valid(&t))
                        return -EINVAL;
-               timeout = timespec_to_jiffies(&t) + 1;
+               if (op == FUTEX_WAIT)
+                       timeout = timespec_to_jiffies(&t) + 1;
+               else {
+                       timeout = t.tv_sec;
+                       val2 = t.tv_nsec;
+               }
        }
        /*
         * requeue parameter in 'utime' if op == FUTEX_REQUEUE.
         */
-       if (op >= FUTEX_REQUEUE)
-               val2 = (int) (unsigned long) utime;
+       if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
+               val2 = (u32) (unsigned long) utime;
 
-       return do_futex((unsigned long)uaddr, op, val, timeout,
-                       (unsigned long)uaddr2, val2, val3);
+       return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
 }
 
 static int futexfs_get_sb(struct file_system_type *fs_type,
index 1ab6a0ea3d14776e9a84d3b8af71ffd418da5498..d1d92b441fb7d7a327f229def2db99d4359063ee 100644 (file)
@@ -129,16 +129,20 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
        unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
        int val2 = 0;
 
-       if (utime && (op == FUTEX_WAIT)) {
+       if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
                if (get_compat_timespec(&t, utime))
                        return -EFAULT;
                if (!timespec_valid(&t))
                        return -EINVAL;
-               timeout = timespec_to_jiffies(&t) + 1;
+               if (op == FUTEX_WAIT)
+                       timeout = timespec_to_jiffies(&t) + 1;
+               else {
+                       timeout = t.tv_sec;
+                       val2 = t.tv_nsec;
+               }
        }
-       if (op >= FUTEX_REQUEUE)
+       if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
                val2 = (int) (unsigned long) utime;
 
-       return do_futex((unsigned long)uaddr, op, val, timeout,
-                       (unsigned long)uaddr2, val2, val3);
+       return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
 }
index 55601b3ce60e92717fa6c6d771bc1a67dea7a03e..8d3dc29ef41ae1fb616d4d8765cb1d077c862852 100644 (file)
@@ -833,7 +833,7 @@ static void migrate_hrtimers(int cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static int hrtimer_cpu_notify(struct notifier_block *self,
+static int __devinit hrtimer_cpu_notify(struct notifier_block *self,
                                        unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
@@ -857,7 +857,7 @@ static int hrtimer_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block hrtimers_nb = {
+static struct notifier_block __devinitdata hrtimers_nb = {
        .notifier_call = hrtimer_cpu_notify,
 };
 
index 9f77f50d814317409f1ed02ce73372bfb428c99f..1dab0ac3f79782a129dc5736ac8d838ee9d4ba01 100644 (file)
@@ -1,5 +1,5 @@
 
-obj-y := handle.o manage.o spurious.o
+obj-y := handle.o manage.o spurious.o resend.o chip.o
 obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
index 3467097ca61ae476a74a7eb1519950acc9a8ebcf..533068cfb607fad10202210b916909efd314cbb7 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 
+#include "internals.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);
+static DEFINE_MUTEX(probing_active);
 
 /**
  *     probe_irq_on    - begin an interrupt autodetect
@@ -27,11 +29,11 @@ static DECLARE_MUTEX(probe_sem);
  */
 unsigned long probe_irq_on(void)
 {
-       unsigned long val;
-       irq_desc_t *desc;
+       struct irq_desc *desc;
+       unsigned long mask;
        unsigned int i;
 
-       down(&probe_sem);
+       mutex_lock(&probing_active);
        /*
         * something may have generated an irq long ago and we want to
         * flush such a longstanding irq before considering it as spurious.
@@ -40,8 +42,21 @@ unsigned long probe_irq_on(void)
                desc = irq_desc + i;
 
                spin_lock_irq(&desc->lock);
-               if (!irq_desc[i].action)
-                       irq_desc[i].handler->startup(i);
+               if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
+                       /*
+                        * An old-style architecture might still have
+                        * the handle_bad_irq handler there:
+                        */
+                       compat_irq_chip_set_default_handler(desc);
+
+                       /*
+                        * Some chips need to know about probing in
+                        * progress:
+                        */
+                       if (desc->chip->set_type)
+                               desc->chip->set_type(i, IRQ_TYPE_PROBE);
+                       desc->chip->startup(i);
+               }
                spin_unlock_irq(&desc->lock);
        }
 
@@ -57,9 +72,9 @@ unsigned long probe_irq_on(void)
                desc = irq_desc + i;
 
                spin_lock_irq(&desc->lock);
-               if (!desc->action) {
+               if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
                        desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
-                       if (desc->handler->startup(i))
+                       if (desc->chip->startup(i))
                                desc->status |= IRQ_PENDING;
                }
                spin_unlock_irq(&desc->lock);
@@ -73,11 +88,11 @@ unsigned long probe_irq_on(void)
        /*
         * Now filter out any obviously spurious interrupts
         */
-       val = 0;
+       mask = 0;
        for (i = 0; i < NR_IRQS; i++) {
-               irq_desc_t *desc = irq_desc + i;
                unsigned int status;
 
+               desc = irq_desc + i;
                spin_lock_irq(&desc->lock);
                status = desc->status;
 
@@ -85,17 +100,16 @@ unsigned long probe_irq_on(void)
                        /* It triggered already - consider it spurious. */
                        if (!(status & IRQ_WAITING)) {
                                desc->status = status & ~IRQ_AUTODETECT;
-                               desc->handler->shutdown(i);
+                               desc->chip->shutdown(i);
                        } else
                                if (i < 32)
-                                       val |= 1 << i;
+                                       mask |= 1 << i;
                }
                spin_unlock_irq(&desc->lock);
        }
 
-       return val;
+       return mask;
 }
-
 EXPORT_SYMBOL(probe_irq_on);
 
 /**
@@ -117,7 +131,7 @@ unsigned int probe_irq_mask(unsigned long val)
 
        mask = 0;
        for (i = 0; i < NR_IRQS; i++) {
-               irq_desc_t *desc = irq_desc + i;
+               struct irq_desc *desc = irq_desc + i;
                unsigned int status;
 
                spin_lock_irq(&desc->lock);
@@ -128,11 +142,11 @@ unsigned int probe_irq_mask(unsigned long val)
                                mask |= 1 << i;
 
                        desc->status = status & ~IRQ_AUTODETECT;
-                       desc->handler->shutdown(i);
+                       desc->chip->shutdown(i);
                }
                spin_unlock_irq(&desc->lock);
        }
-       up(&probe_sem);
+       mutex_unlock(&probing_active);
 
        return mask & val;
 }
@@ -160,7 +174,7 @@ 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;
+               struct irq_desc *desc = irq_desc + i;
                unsigned int status;
 
                spin_lock_irq(&desc->lock);
@@ -173,16 +187,16 @@ int probe_irq_off(unsigned long val)
                                nr_irqs++;
                        }
                        desc->status = status & ~IRQ_AUTODETECT;
-                       desc->handler->shutdown(i);
+                       desc->chip->shutdown(i);
                }
                spin_unlock_irq(&desc->lock);
        }
-       up(&probe_sem);
+       mutex_unlock(&probing_active);
 
        if (nr_irqs > 1)
                irq_found = -irq_found;
+
        return irq_found;
 }
-
 EXPORT_SYMBOL(probe_irq_off);
 
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
new file mode 100644 (file)
index 0000000..4a0952d
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * linux/kernel/irq/chip.c
+ *
+ * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 2005-2006, Thomas Gleixner, Russell King
+ *
+ * This file contains the core interrupt handling code, for irq-chip
+ * based architectures.
+ *
+ * Detailed information is available in Documentation/DocBook/genericirq
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include "internals.h"
+
+/**
+ *     set_irq_chip - set the irq chip for an irq
+ *     @irq:   irq number
+ *     @chip:  pointer to irq chip description structure
+ */
+int set_irq_chip(unsigned int irq, struct irq_chip *chip)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       if (!chip)
+               chip = &no_irq_chip;
+
+       desc = irq_desc + irq;
+       spin_lock_irqsave(&desc->lock, flags);
+       irq_chip_set_defaults(chip);
+       desc->chip = chip;
+       /*
+        * For compatibility only:
+        */
+       desc->chip = chip;
+       spin_unlock_irqrestore(&desc->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(set_irq_chip);
+
+/**
+ *     set_irq_type - set the irq type for an irq
+ *     @irq:   irq number
+ *     @type:  interrupt type - see include/linux/interrupt.h
+ */
+int set_irq_type(unsigned int irq, unsigned int type)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+       int ret = -ENXIO;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
+               return -ENODEV;
+       }
+
+       desc = irq_desc + irq;
+       if (desc->chip->set_type) {
+               spin_lock_irqsave(&desc->lock, flags);
+               ret = desc->chip->set_type(irq, type);
+               spin_unlock_irqrestore(&desc->lock, flags);
+       }
+       return ret;
+}
+EXPORT_SYMBOL(set_irq_type);
+
+/**
+ *     set_irq_data - set irq type data for an irq
+ *     @irq:   Interrupt number
+ *     @data:  Pointer to interrupt specific data
+ *
+ *     Set the hardware irq controller data for an irq
+ */
+int set_irq_data(unsigned int irq, void *data)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_ERR
+                      "Trying to install controller data for IRQ%d\n", irq);
+               return -EINVAL;
+       }
+
+       desc = irq_desc + irq;
+       spin_lock_irqsave(&desc->lock, flags);
+       desc->handler_data = data;
+       spin_unlock_irqrestore(&desc->lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL(set_irq_data);
+
+/**
+ *     set_irq_chip_data - set irq chip data for an irq
+ *     @irq:   Interrupt number
+ *     @data:  Pointer to chip specific data
+ *
+ *     Set the hardware irq chip data for an irq
+ */
+int set_irq_chip_data(unsigned int irq, void *data)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS || !desc->chip) {
+               printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&desc->lock, flags);
+       desc->chip_data = data;
+       spin_unlock_irqrestore(&desc->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(set_irq_chip_data);
+
+/*
+ * default enable function
+ */
+static void default_enable(unsigned int irq)
+{
+       struct irq_desc *desc = irq_desc + irq;
+
+       desc->chip->unmask(irq);
+       desc->status &= ~IRQ_MASKED;
+}
+
+/*
+ * default disable function
+ */
+static void default_disable(unsigned int irq)
+{
+       struct irq_desc *desc = irq_desc + irq;
+
+       if (!(desc->status & IRQ_DELAYED_DISABLE))
+               irq_desc[irq].chip->mask(irq);
+}
+
+/*
+ * default startup function
+ */
+static unsigned int default_startup(unsigned int irq)
+{
+       irq_desc[irq].chip->enable(irq);
+
+       return 0;
+}
+
+/*
+ * Fixup enable/disable function pointers
+ */
+void irq_chip_set_defaults(struct irq_chip *chip)
+{
+       if (!chip->enable)
+               chip->enable = default_enable;
+       if (!chip->disable)
+               chip->disable = default_disable;
+       if (!chip->startup)
+               chip->startup = default_startup;
+       if (!chip->shutdown)
+               chip->shutdown = chip->disable;
+       if (!chip->name)
+               chip->name = chip->typename;
+}
+
+static inline void mask_ack_irq(struct irq_desc *desc, int irq)
+{
+       if (desc->chip->mask_ack)
+               desc->chip->mask_ack(irq);
+       else {
+               desc->chip->mask(irq);
+               desc->chip->ack(irq);
+       }
+}
+
+/**
+ *     handle_simple_irq - Simple and software-decoded IRQs.
+ *     @irq:   the interrupt number
+ *     @desc:  the interrupt description structure for this irq
+ *     @regs:  pointer to a register structure
+ *
+ *     Simple interrupts are either sent from a demultiplexing interrupt
+ *     handler or come from hardware, where no interrupt hardware control
+ *     is necessary.
+ *
+ *     Note: The caller is expected to handle the ack, clear, mask and
+ *     unmask issues if necessary.
+ */
+void fastcall
+handle_simple_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+       struct irqaction *action;
+       irqreturn_t action_ret;
+       const unsigned int cpu = smp_processor_id();
+
+       spin_lock(&desc->lock);
+
+       if (unlikely(desc->status & IRQ_INPROGRESS))
+               goto out_unlock;
+       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+       kstat_cpu(cpu).irqs[irq]++;
+
+       action = desc->action;
+       if (unlikely(!action || (desc->status & IRQ_DISABLED)))
+               goto out_unlock;
+
+       desc->status |= IRQ_INPROGRESS;
+       spin_unlock(&desc->lock);
+
+       action_ret = handle_IRQ_event(irq, regs, action);
+       if (!noirqdebug)
+               note_interrupt(irq, desc, action_ret, regs);
+
+       spin_lock(&desc->lock);
+       desc->status &= ~IRQ_INPROGRESS;
+out_unlock:
+       spin_unlock(&desc->lock);
+}
+
+/**
+ *     handle_level_irq - Level type irq handler
+ *     @irq:   the interrupt number
+ *     @desc:  the interrupt description structure for this irq
+ *     @regs:  pointer to a register structure
+ *
+ *     Level type interrupts are active as long as the hardware line has
+ *     the active level. This may require to mask the interrupt and unmask
+ *     it after the associated handler has acknowledged the device, so the
+ *     interrupt line is back to inactive.
+ */
+void fastcall
+handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+       unsigned int cpu = smp_processor_id();
+       struct irqaction *action;
+       irqreturn_t action_ret;
+
+       spin_lock(&desc->lock);
+       mask_ack_irq(desc, irq);
+
+       if (unlikely(desc->status & IRQ_INPROGRESS))
+               goto out;
+       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+       kstat_cpu(cpu).irqs[irq]++;
+
+       /*
+        * If its disabled or no action available
+        * keep it masked and get out of here
+        */
+       action = desc->action;
+       if (unlikely(!action || (desc->status & IRQ_DISABLED)))
+               goto out;
+
+       desc->status |= IRQ_INPROGRESS;
+       spin_unlock(&desc->lock);
+
+       action_ret = handle_IRQ_event(irq, regs, action);
+       if (!noirqdebug)
+               note_interrupt(irq, desc, action_ret, regs);
+
+       spin_lock(&desc->lock);
+       desc->status &= ~IRQ_INPROGRESS;
+out:
+       if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+               desc->chip->unmask(irq);
+       spin_unlock(&desc->lock);
+}
+
+/**
+ *     handle_fasteoi_irq - irq handler for transparent controllers
+ *     @irq:   the interrupt number
+ *     @desc:  the interrupt description structure for this irq
+ *     @regs:  pointer to a register structure
+ *
+ *     Only a single callback will be issued to the chip: an ->eoi()
+ *     call when the interrupt has been serviced. This enables support
+ *     for modern forms of interrupt handlers, which handle the flow
+ *     details in hardware, transparently.
+ */
+void fastcall
+handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc,
+                  struct pt_regs *regs)
+{
+       unsigned int cpu = smp_processor_id();
+       struct irqaction *action;
+       irqreturn_t action_ret;
+
+       spin_lock(&desc->lock);
+
+       if (unlikely(desc->status & IRQ_INPROGRESS))
+               goto out;
+
+       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+       kstat_cpu(cpu).irqs[irq]++;
+
+       /*
+        * If its disabled or no action available
+        * keep it masked and get out of here
+        */
+       action = desc->action;
+       if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
+               desc->status |= IRQ_PENDING;
+               goto out;
+       }
+
+       desc->status |= IRQ_INPROGRESS;
+       desc->status &= ~IRQ_PENDING;
+       spin_unlock(&desc->lock);
+
+       action_ret = handle_IRQ_event(irq, regs, action);
+       if (!noirqdebug)
+               note_interrupt(irq, desc, action_ret, regs);
+
+       spin_lock(&desc->lock);
+       desc->status &= ~IRQ_INPROGRESS;
+out:
+       desc->chip->eoi(irq);
+
+       spin_unlock(&desc->lock);
+}
+
+/**
+ *     handle_edge_irq - edge type IRQ handler
+ *     @irq:   the interrupt number
+ *     @desc:  the interrupt description structure for this irq
+ *     @regs:  pointer to a register structure
+ *
+ *     Interrupt occures on the falling and/or rising edge of a hardware
+ *     signal. The occurence is latched into the irq controller hardware
+ *     and must be acked in order to be reenabled. After the ack another
+ *     interrupt can happen on the same source even before the first one
+ *     is handled by the assosiacted event handler. If this happens it
+ *     might be necessary to disable (mask) the interrupt depending on the
+ *     controller hardware. This requires to reenable the interrupt inside
+ *     of the loop which handles the interrupts which have arrived while
+ *     the handler was running. If all pending interrupts are handled, the
+ *     loop is left.
+ */
+void fastcall
+handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+       const unsigned int cpu = smp_processor_id();
+
+       spin_lock(&desc->lock);
+
+       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+
+       /*
+        * If we're currently running this IRQ, or its disabled,
+        * we shouldn't process the IRQ. Mark it pending, handle
+        * the necessary masking and go out
+        */
+       if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||
+                   !desc->action)) {
+               desc->status |= (IRQ_PENDING | IRQ_MASKED);
+               mask_ack_irq(desc, irq);
+               goto out_unlock;
+       }
+
+       kstat_cpu(cpu).irqs[irq]++;
+
+       /* Start handling the irq */
+       desc->chip->ack(irq);
+
+       /* Mark the IRQ currently in progress.*/
+       desc->status |= IRQ_INPROGRESS;
+
+       do {
+               struct irqaction *action = desc->action;
+               irqreturn_t action_ret;
+
+               if (unlikely(!action)) {
+                       desc->chip->mask(irq);
+                       goto out_unlock;
+               }
+
+               /*
+                * When another irq arrived while we were handling
+                * one, we could have masked the irq.
+                * Renable it, if it was not disabled in meantime.
+                */
+               if (unlikely((desc->status &
+                              (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
+                             (IRQ_PENDING | IRQ_MASKED))) {
+                       desc->chip->unmask(irq);
+                       desc->status &= ~IRQ_MASKED;
+               }
+
+               desc->status &= ~IRQ_PENDING;
+               spin_unlock(&desc->lock);
+               action_ret = handle_IRQ_event(irq, regs, action);
+               if (!noirqdebug)
+                       note_interrupt(irq, desc, action_ret, regs);
+               spin_lock(&desc->lock);
+
+       } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
+
+       desc->status &= ~IRQ_INPROGRESS;
+out_unlock:
+       spin_unlock(&desc->lock);
+}
+
+#ifdef CONFIG_SMP
+/**
+ *     handle_percpu_IRQ - Per CPU local irq handler
+ *     @irq:   the interrupt number
+ *     @desc:  the interrupt description structure for this irq
+ *     @regs:  pointer to a register structure
+ *
+ *     Per CPU interrupts on SMP machines without locking requirements
+ */
+void fastcall
+handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+       irqreturn_t action_ret;
+
+       kstat_this_cpu.irqs[irq]++;
+
+       if (desc->chip->ack)
+               desc->chip->ack(irq);
+
+       action_ret = handle_IRQ_event(irq, regs, desc->action);
+       if (!noirqdebug)
+               note_interrupt(irq, desc, action_ret, regs);
+
+       if (desc->chip->eoi)
+               desc->chip->eoi(irq);
+}
+
+#endif /* CONFIG_SMP */
+
+void
+__set_irq_handler(unsigned int irq,
+                 void fastcall (*handle)(unsigned int, irq_desc_t *,
+                                         struct pt_regs *),
+                 int is_chained)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_ERR
+                      "Trying to install type control for IRQ%d\n", irq);
+               return;
+       }
+
+       desc = irq_desc + irq;
+
+       if (!handle)
+               handle = handle_bad_irq;
+
+       if (is_chained && desc->chip == &no_irq_chip)
+               printk(KERN_WARNING "Trying to install "
+                      "chained interrupt type for IRQ%d\n", irq);
+
+       spin_lock_irqsave(&desc->lock, flags);
+
+       /* Uninstall? */
+       if (handle == handle_bad_irq) {
+               if (desc->chip != &no_irq_chip) {
+                       desc->chip->mask(irq);
+                       desc->chip->ack(irq);
+               }
+               desc->status |= IRQ_DISABLED;
+               desc->depth = 1;
+       }
+       desc->handle_irq = handle;
+
+       if (handle != handle_bad_irq && is_chained) {
+               desc->status &= ~IRQ_DISABLED;
+               desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
+               desc->depth = 0;
+               desc->chip->unmask(irq);
+       }
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+void
+set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
+                        void fastcall (*handle)(unsigned int,
+                                                struct irq_desc *,
+                                                struct pt_regs *))
+{
+       set_irq_chip(irq, chip);
+       __set_irq_handler(irq, handle, 0);
+}
+
+/*
+ * Get a descriptive string for the highlevel handler, for
+ * /proc/interrupts output:
+ */
+const char *
+handle_irq_name(void fastcall (*handle)(unsigned int, struct irq_desc *,
+                                       struct pt_regs *))
+{
+       if (handle == handle_level_irq)
+               return "level  ";
+       if (handle == handle_fasteoi_irq)
+               return "fasteoi";
+       if (handle == handle_edge_irq)
+               return "edge   ";
+       if (handle == handle_simple_irq)
+               return "simple ";
+#ifdef CONFIG_SMP
+       if (handle == handle_percpu_irq)
+               return "percpu ";
+#endif
+       if (handle == handle_bad_irq)
+               return "bad    ";
+
+       return NULL;
+}
index 0f6530117105c6f000668c3bcae8ca8be1b6e4bd..5a360dd4331b0505a6f4e54c0c26317f23d3c189 100644 (file)
@@ -1,9 +1,13 @@
 /*
  * linux/kernel/irq/handle.c
  *
- * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 2005-2006, Thomas Gleixner, Russell King
  *
  * This file contains the core interrupt handling code.
+ *
+ * Detailed information is available in Documentation/DocBook/genericirq
+ *
  */
 
 #include <linux/irq.h>
 
 #include "internals.h"
 
+/**
+ * handle_bad_irq - handle spurious and unhandled irqs
+ */
+void fastcall
+handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+{
+       print_irq_desc(irq, desc);
+       kstat_this_cpu.irqs[irq]++;
+       ack_bad_irq(irq);
+}
+
 /*
  * 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
+ * interrupt source is transparently wired to the appropriate
  * controller. Thus drivers need not be aware of the
  * interrupt-controller.
  *
  *
  * Controller mappings for all interrupt sources:
  */
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
+struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned = {
        [0 ... NR_IRQS-1] = {
                .status = IRQ_DISABLED,
-               .handler = &no_irq_type,
-               .lock = SPIN_LOCK_UNLOCKED
+               .chip = &no_irq_chip,
+               .handle_irq = handle_bad_irq,
+               .depth = 1,
+               .lock = SPIN_LOCK_UNLOCKED,
+#ifdef CONFIG_SMP
+               .affinity = CPU_MASK_ALL
+#endif
        }
 };
 
 /*
- * Generic 'no controller' code
+ * What should we do if we get a hw irq event on an illegal vector?
+ * Each architecture has to answer this themself.
  */
-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)
+static void ack_bad(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.
-        */
+       print_irq_desc(irq, irq_desc + irq);
        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
+/*
+ * NOP functions
+ */
+static void noop(unsigned int irq)
+{
+}
+
+static unsigned int noop_ret(unsigned int irq)
+{
+       return 0;
+}
+
+/*
+ * Generic no controller implementation
+ */
+struct irq_chip no_irq_chip = {
+       .name           = "none",
+       .startup        = noop_ret,
+       .shutdown       = noop,
+       .enable         = noop,
+       .disable        = noop,
+       .ack            = ack_bad,
+       .end            = noop,
 };
 
 /*
@@ -73,11 +99,16 @@ irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
        return IRQ_NONE;
 }
 
-/*
- * Have got an event to handle:
+/**
+ * handle_IRQ_event - irq action chain handler
+ * @irq:       the interrupt number
+ * @regs:      pointer to a register structure
+ * @action:    the interrupt action chain for this irq
+ *
+ * Handles the action chain of an irq event
  */
-fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
-                               struct irqaction *action)
+irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+                            struct irqaction *action)
 {
        irqreturn_t ret, retval = IRQ_NONE;
        unsigned int status = 0;
@@ -100,15 +131,22 @@ fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
        return retval;
 }
 
-/*
- * do_IRQ handles all normal device IRQ's (the special
+/**
+ * __do_IRQ - original all in one highlevel IRQ handler
+ * @irq:       the interrupt number
+ * @regs:      pointer to a register structure
+ *
+ * __do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
  * handlers).
+ *
+ * This is the original x86 implementation which is used for every
+ * interrupt type.
  */
 fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
 {
-       irq_desc_t *desc = irq_desc + irq;
-       struct irqaction * action;
+       struct irq_desc *desc = irq_desc + irq;
+       struct irqaction *action;
        unsigned int status;
 
        kstat_this_cpu.irqs[irq]++;
@@ -118,16 +156,16 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
                /*
                 * No locking required for CPU-local interrupts:
                 */
-               if (desc->handler->ack)
-                       desc->handler->ack(irq);
+               if (desc->chip->ack)
+                       desc->chip->ack(irq);
                action_ret = handle_IRQ_event(irq, regs, desc->action);
-               desc->handler->end(irq);
+               desc->chip->end(irq);
                return 1;
        }
 
        spin_lock(&desc->lock);
-       if (desc->handler->ack)
-               desc->handler->ack(irq);
+       if (desc->chip->ack)
+               desc->chip->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
@@ -187,7 +225,7 @@ out:
         * The ->end() handler has to deal with interrupts which got
         * disabled while the handler was running.
         */
-       desc->handler->end(irq);
+       desc->chip->end(irq);
        spin_unlock(&desc->lock);
 
        return 1;
index 46feba630266eedb5ac55b83d5dfdbf86b3c7d0c..08a849a224475102084ca807de6861b6ab7286b5 100644 (file)
@@ -4,6 +4,12 @@
 
 extern int noirqdebug;
 
+/* Set default functions for irq_chip structures: */
+extern void irq_chip_set_defaults(struct irq_chip *chip);
+
+/* Set default handler: */
+extern void compat_irq_chip_set_default_handler(struct irq_desc *desc);
+
 #ifdef CONFIG_PROC_FS
 extern void register_irq_proc(unsigned int irq);
 extern void register_handler_proc(unsigned int irq, struct irqaction *action);
@@ -16,3 +22,43 @@ static inline void unregister_handler_proc(unsigned int irq,
                                           struct irqaction *action) { }
 #endif
 
+/*
+ * Debugging printout:
+ */
+
+#include <linux/kallsyms.h>
+
+#define P(f) if (desc->status & f) printk("%14s set\n", #f)
+
+static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc)
+{
+       printk("irq %d, desc: %p, depth: %d, count: %d, unhandled: %d\n",
+               irq, desc, desc->depth, desc->irq_count, desc->irqs_unhandled);
+       printk("->handle_irq():  %p, ", desc->handle_irq);
+       print_symbol("%s\n", (unsigned long)desc->handle_irq);
+       printk("->chip(): %p, ", desc->chip);
+       print_symbol("%s\n", (unsigned long)desc->chip);
+       printk("->action(): %p\n", desc->action);
+       if (desc->action) {
+               printk("->action->handler(): %p, ", desc->action->handler);
+               print_symbol("%s\n", (unsigned long)desc->action->handler);
+       }
+
+       P(IRQ_INPROGRESS);
+       P(IRQ_DISABLED);
+       P(IRQ_PENDING);
+       P(IRQ_REPLAY);
+       P(IRQ_AUTODETECT);
+       P(IRQ_WAITING);
+       P(IRQ_LEVEL);
+       P(IRQ_MASKED);
+#ifdef CONFIG_IRQ_PER_CPU
+       P(IRQ_PER_CPU);
+#endif
+       P(IRQ_NOPROBE);
+       P(IRQ_NOREQUEST);
+       P(IRQ_NOAUTOEN);
+}
+
+#undef P
+
index 1279e3499534d490212053812a64671a59b3132d..9eb1d518ee1c8dc8da68f7903cd207482352e8fa 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * linux/kernel/irq/manage.c
  *
- * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 2005-2006 Thomas Gleixner
  *
  * This file contains driver APIs to the irq subsystem.
  */
 
 #ifdef CONFIG_SMP
 
-cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
-
-#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
-cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS];
-#endif
-
 /**
  *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
  *     @irq: interrupt number to wait for
@@ -42,7 +37,6 @@ void synchronize_irq(unsigned int irq)
        while (desc->status & IRQ_INPROGRESS)
                cpu_relax();
 }
-
 EXPORT_SYMBOL(synchronize_irq);
 
 #endif
@@ -60,7 +54,7 @@ EXPORT_SYMBOL(synchronize_irq);
  */
 void disable_irq_nosync(unsigned int irq)
 {
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
        unsigned long flags;
 
        if (irq >= NR_IRQS)
@@ -69,11 +63,10 @@ void disable_irq_nosync(unsigned int irq)
        spin_lock_irqsave(&desc->lock, flags);
        if (!desc->depth++) {
                desc->status |= IRQ_DISABLED;
-               desc->handler->disable(irq);
+               desc->chip->disable(irq);
        }
        spin_unlock_irqrestore(&desc->lock, flags);
 }
-
 EXPORT_SYMBOL(disable_irq_nosync);
 
 /**
@@ -90,7 +83,7 @@ EXPORT_SYMBOL(disable_irq_nosync);
  */
 void disable_irq(unsigned int irq)
 {
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
 
        if (irq >= NR_IRQS)
                return;
@@ -99,7 +92,6 @@ void disable_irq(unsigned int irq)
        if (desc->action)
                synchronize_irq(irq);
 }
-
 EXPORT_SYMBOL(disable_irq);
 
 /**
@@ -114,7 +106,7 @@ EXPORT_SYMBOL(disable_irq);
  */
 void enable_irq(unsigned int irq)
 {
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
        unsigned long flags;
 
        if (irq >= NR_IRQS)
@@ -123,17 +115,15 @@ void enable_irq(unsigned int irq)
        spin_lock_irqsave(&desc->lock, flags);
        switch (desc->depth) {
        case 0:
+               printk(KERN_WARNING "Unablanced enable_irq(%d)\n", irq);
                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);
+               /* Prevent probing on this irq: */
+               desc->status = status | IRQ_NOPROBE;
+               check_irq_resend(desc, irq);
                /* fall-through */
        }
        default:
@@ -141,9 +131,29 @@ void enable_irq(unsigned int irq)
        }
        spin_unlock_irqrestore(&desc->lock, flags);
 }
-
 EXPORT_SYMBOL(enable_irq);
 
+/**
+ *     set_irq_wake - control irq power management wakeup
+ *     @irq:   interrupt to control
+ *     @on:    enable/disable power management wakeup
+ *
+ *     Enable/disable power management wakeup mode
+ */
+int set_irq_wake(unsigned int irq, unsigned int on)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       unsigned long flags;
+       int ret = -ENXIO;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       if (desc->chip->set_wake)
+               ret = desc->chip->set_wake(irq, on);
+       spin_unlock_irqrestore(&desc->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL(set_irq_wake);
+
 /*
  * Internal function that tells the architecture code whether a
  * particular irq has been exclusively allocated or is available
@@ -153,7 +163,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
 {
        struct irqaction *action;
 
-       if (irq >= NR_IRQS)
+       if (irq >= NR_IRQS || irq_desc[irq].status & IRQ_NOREQUEST)
                return 0;
 
        action = irq_desc[irq].action;
@@ -164,11 +174,22 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
        return !action;
 }
 
+void compat_irq_chip_set_default_handler(struct irq_desc *desc)
+{
+       /*
+        * If the architecture still has not overriden
+        * the flow handler then zap the default. This
+        * should catch incorrect flow-type setting.
+        */
+       if (desc->handle_irq == &handle_bad_irq)
+               desc->handle_irq = NULL;
+}
+
 /*
  * 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)
+int setup_irq(unsigned int irq, struct irqaction *new)
 {
        struct irq_desc *desc = irq_desc + irq;
        struct irqaction *old, **p;
@@ -178,7 +199,7 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        if (irq >= NR_IRQS)
                return -EINVAL;
 
-       if (desc->handler == &no_irq_type)
+       if (desc->chip == &no_irq_chip)
                return -ENOSYS;
        /*
         * Some drivers like serial.c use request_irq() heavily,
@@ -200,14 +221,21 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        /*
         * The following block of code has to be executed atomically
         */
-       spin_lock_irqsave(&desc->lock,flags);
+       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))
+       old = *p;
+       if (old) {
+               /*
+                * Can't share interrupts unless both agree to and are
+                * the same type (level, edge, polarity). So both flag
+                * fields must have SA_SHIRQ set and the bits which
+                * set the trigger type must match.
+                */
+               if (!((old->flags & new->flags) & SA_SHIRQ) ||
+                   ((old->flags ^ new->flags) & SA_TRIGGER_MASK))
                        goto mismatch;
 
-#if defined(ARCH_HAS_IRQ_PER_CPU) && defined(SA_PERCPU_IRQ)
+#if defined(CONFIG_IRQ_PER_CPU) && defined(SA_PERCPU_IRQ)
                /* All handlers must agree on per-cpuness */
                if ((old->flags & IRQ_PER_CPU) != (new->flags & IRQ_PER_CPU))
                        goto mismatch;
@@ -222,20 +250,44 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        }
 
        *p = new;
-#if defined(ARCH_HAS_IRQ_PER_CPU) && defined(SA_PERCPU_IRQ)
+#if defined(CONFIG_IRQ_PER_CPU) && defined(SA_PERCPU_IRQ)
        if (new->flags & SA_PERCPU_IRQ)
                desc->status |= IRQ_PER_CPU;
 #endif
        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);
+               irq_chip_set_defaults(desc->chip);
+
+               /* Setup the type (level, edge polarity) if configured: */
+               if (new->flags & SA_TRIGGER_MASK) {
+                       if (desc->chip && desc->chip->set_type)
+                               desc->chip->set_type(irq,
+                                               new->flags & SA_TRIGGER_MASK);
+                       else
+                               /*
+                                * SA_TRIGGER_* but the PIC does not support
+                                * multiple flow-types?
+                                */
+                               printk(KERN_WARNING "setup_irq(%d) SA_TRIGGER"
+                                      "set. No set_type function available\n",
+                                      irq);
+               } else
+                       compat_irq_chip_set_default_handler(desc);
+
+               desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
+                                 IRQ_INPROGRESS);
+
+               if (!(desc->status & IRQ_NOAUTOEN)) {
+                       desc->depth = 0;
+                       desc->status &= ~IRQ_DISABLED;
+                       if (desc->chip->startup)
+                               desc->chip->startup(irq);
+                       else
+                               desc->chip->enable(irq);
+               } else
+                       /* Undo nested disables: */
+                       desc->depth = 1;
        }
-       spin_unlock_irqrestore(&desc->lock,flags);
+       spin_unlock_irqrestore(&desc->lock, flags);
 
        new->irq = irq;
        register_irq_proc(irq);
@@ -278,10 +330,10 @@ void free_irq(unsigned int irq, void *dev_id)
                return;
 
        desc = irq_desc + irq;
-       spin_lock_irqsave(&desc->lock,flags);
+       spin_lock_irqsave(&desc->lock, flags);
        p = &desc->action;
        for (;;) {
-               struct irqaction * action = *p;
+               struct irqaction *action = *p;
 
                if (action) {
                        struct irqaction **pp = p;
@@ -295,18 +347,18 @@ void free_irq(unsigned int irq, void *dev_id)
 
                        /* Currently used only by UML, might disappear one day.*/
 #ifdef CONFIG_IRQ_RELEASE_METHOD
-                       if (desc->handler->release)
-                               desc->handler->release(irq, dev_id);
+                       if (desc->chip->release)
+                               desc->chip->release(irq, dev_id);
 #endif
 
                        if (!desc->action) {
                                desc->status |= IRQ_DISABLED;
-                               if (desc->handler->shutdown)
-                                       desc->handler->shutdown(irq);
+                               if (desc->chip->shutdown)
+                                       desc->chip->shutdown(irq);
                                else
-                                       desc->handler->disable(irq);
+                                       desc->chip->disable(irq);
                        }
-                       spin_unlock_irqrestore(&desc->lock,flags);
+                       spin_unlock_irqrestore(&desc->lock, flags);
                        unregister_handler_proc(irq, action);
 
                        /* Make sure it's not being used on another CPU */
@@ -314,12 +366,11 @@ void free_irq(unsigned int irq, void *dev_id)
                        kfree(action);
                        return;
                }
-               printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
-               spin_unlock_irqrestore(&desc->lock,flags);
+               printk(KERN_ERR "Trying to free free IRQ%d\n", irq);
+               spin_unlock_irqrestore(&desc->lock, flags);
                return;
        }
 }
-
 EXPORT_SYMBOL(free_irq);
 
 /**
@@ -353,9 +404,9 @@ EXPORT_SYMBOL(free_irq);
  */
 int request_irq(unsigned int irq,
                irqreturn_t (*handler)(int, void *, struct pt_regs *),
-               unsigned long irqflags, const char * devname, void *dev_id)
+               unsigned long irqflags, const char *devname, void *dev_id)
 {
-       struct irqaction * action;
+       struct irqaction *action;
        int retval;
 
        /*
@@ -368,6 +419,8 @@ int request_irq(unsigned int irq,
                return -EINVAL;
        if (irq >= NR_IRQS)
                return -EINVAL;
+       if (irq_desc[irq].status & IRQ_NOREQUEST)
+               return -EINVAL;
        if (!handler)
                return -EINVAL;
 
@@ -390,6 +443,5 @@ int request_irq(unsigned int irq,
 
        return retval;
 }
-
 EXPORT_SYMBOL(request_irq);
 
index a12d00eb5e7c01e9495704fbfdae248ab081ed8e..a57ebe9fa6f6b89169eb7e7e093167c341caed71 100644 (file)
@@ -3,19 +3,19 @@
 
 void set_pending_irq(unsigned int irq, cpumask_t mask)
 {
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
        unsigned long flags;
 
        spin_lock_irqsave(&desc->lock, flags);
        desc->move_irq = 1;
-       pending_irq_cpumask[irq] = mask;
+       irq_desc[irq].pending_mask = mask;
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 
 void move_native_irq(int irq)
 {
+       struct irq_desc *desc = irq_desc + irq;
        cpumask_t tmp;
-       irq_desc_t *desc = irq_descp(irq);
 
        if (likely(!desc->move_irq))
                return;
@@ -30,15 +30,15 @@ void move_native_irq(int irq)
 
        desc->move_irq = 0;
 
-       if (unlikely(cpus_empty(pending_irq_cpumask[irq])))
+       if (unlikely(cpus_empty(irq_desc[irq].pending_mask)))
                return;
 
-       if (!desc->handler->set_affinity)
+       if (!desc->chip->set_affinity)
                return;
 
        assert_spin_locked(&desc->lock);
 
-       cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
+       cpus_and(tmp, irq_desc[irq].pending_mask, cpu_online_map);
 
        /*
         * If there was a valid mask to work with, please
@@ -51,12 +51,12 @@ void move_native_irq(int irq)
         */
        if (likely(!cpus_empty(tmp))) {
                if (likely(!(desc->status & IRQ_DISABLED)))
-                       desc->handler->disable(irq);
+                       desc->chip->disable(irq);
 
-               desc->handler->set_affinity(irq,tmp);
+               desc->chip->set_affinity(irq,tmp);
 
                if (likely(!(desc->status & IRQ_DISABLED)))
-                       desc->handler->enable(irq);
+                       desc->chip->enable(irq);
        }
-       cpus_clear(pending_irq_cpumask[irq]);
+       cpus_clear(irq_desc[irq].pending_mask);
 }
index afacd6f585fad187cfa950e651ad7e08a0301d81..607c7809ad0125e7aad8d28a308319601a7223ea 100644 (file)
 
 #include "internals.h"
 
-static struct proc_dir_entry *root_irq_dir, *irq_dir[NR_IRQS];
+static struct proc_dir_entry *root_irq_dir;
 
 #ifdef CONFIG_SMP
 
-/*
- * The /proc/irq/<irq>/smp_affinity values:
- */
-static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
-
 #ifdef CONFIG_GENERIC_PENDING_IRQ
 void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
 {
@@ -36,15 +31,15 @@ void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
 void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val)
 {
        set_balance_irq_affinity(irq, mask_val);
-       irq_affinity[irq] = mask_val;
-       irq_desc[irq].handler->set_affinity(irq, mask_val);
+       irq_desc[irq].affinity = mask_val;
+       irq_desc[irq].chip->set_affinity(irq, mask_val);
 }
 #endif
 
 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]);
+       int len = cpumask_scnprintf(page, count, irq_desc[(long)data].affinity);
 
        if (count - len < 2)
                return -EINVAL;
@@ -59,7 +54,7 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
        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)
+       if (!irq_desc[irq].chip->set_affinity || no_irq_affinity)
                return -EIO;
 
        err = cpumask_parse(buffer, count, new_value);
@@ -102,7 +97,7 @@ void register_handler_proc(unsigned int irq, struct irqaction *action)
 {
        char name [MAX_NAMELEN];
 
-       if (!irq_dir[irq] || action->dir || !action->name ||
+       if (!irq_desc[irq].dir || action->dir || !action->name ||
                                        !name_unique(irq, action))
                return;
 
@@ -110,7 +105,7 @@ void register_handler_proc(unsigned int irq, struct irqaction *action)
        snprintf(name, MAX_NAMELEN, "%s", action->name);
 
        /* create /proc/irq/1234/handler/ */
-       action->dir = proc_mkdir(name, irq_dir[irq]);
+       action->dir = proc_mkdir(name, irq_desc[irq].dir);
 }
 
 #undef MAX_NAMELEN
@@ -122,22 +117,22 @@ 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])
+               (irq_desc[irq].chip == &no_irq_chip) ||
+                       irq_desc[irq].dir)
                return;
 
        memset(name, 0, MAX_NAMELEN);
        sprintf(name, "%d", irq);
 
        /* create /proc/irq/1234 */
-       irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+       irq_desc[irq].dir = 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]);
+               entry = create_proc_entry("smp_affinity", 0600, irq_desc[irq].dir);
 
                if (entry) {
                        entry->nlink = 1;
@@ -145,7 +140,6 @@ void register_irq_proc(unsigned int irq)
                        entry->read_proc = irq_affinity_read_proc;
                        entry->write_proc = irq_affinity_write_proc;
                }
-               smp_affinity_entry[irq] = entry;
        }
 #endif
 }
@@ -155,7 +149,7 @@ void register_irq_proc(unsigned int irq)
 void unregister_handler_proc(unsigned int irq, struct irqaction *action)
 {
        if (action->dir)
-               remove_proc_entry(action->dir->name, irq_dir[irq]);
+               remove_proc_entry(action->dir->name, irq_desc[irq].dir);
 }
 
 void init_irq_proc(void)
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c
new file mode 100644 (file)
index 0000000..872f91b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * linux/kernel/irq/resend.c
+ *
+ * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 2005-2006, Thomas Gleixner
+ *
+ * This file contains the IRQ-resend code
+ *
+ * If the interrupt is waiting to be processed, we try to re-run it.
+ * We can't directly run it from here since the caller might be in an
+ * interrupt-protected region. Not all irq controller chips can
+ * retrigger interrupts at the hardware level, so in those cases
+ * we allow the resending of IRQs via a tasklet.
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/interrupt.h>
+
+#include "internals.h"
+
+#ifdef CONFIG_HARDIRQS_SW_RESEND
+
+/* Bitmap to handle software resend of interrupts: */
+static DECLARE_BITMAP(irqs_resend, NR_IRQS);
+
+/*
+ * Run software resends of IRQ's
+ */
+static void resend_irqs(unsigned long arg)
+{
+       struct irq_desc *desc;
+       int irq;
+
+       while (!bitmap_empty(irqs_resend, NR_IRQS)) {
+               irq = find_first_bit(irqs_resend, NR_IRQS);
+               clear_bit(irq, irqs_resend);
+               desc = irq_desc + irq;
+               local_irq_disable();
+               desc->handle_irq(irq, desc, NULL);
+               local_irq_enable();
+       }
+}
+
+/* Tasklet to handle resend: */
+static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0);
+
+#endif
+
+/*
+ * IRQ resend
+ *
+ * Is called with interrupts disabled and desc->lock held.
+ */
+void check_irq_resend(struct irq_desc *desc, unsigned int irq)
+{
+       unsigned int status = desc->status;
+
+       /*
+        * Make sure the interrupt is enabled, before resending it:
+        */
+       desc->chip->enable(irq);
+
+       if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+               desc->status &= ~IRQ_PENDING;
+               desc->status = status | IRQ_REPLAY;
+
+               if (!desc->chip || !desc->chip->retrigger ||
+                                       !desc->chip->retrigger(irq)) {
+#ifdef CONFIG_HARDIRQS_SW_RESEND
+                       /* Set it pending and activate the softirq: */
+                       set_bit(irq, irqs_resend);
+                       tasklet_schedule(&resend_tasklet);
+#endif
+               }
+       }
+}
index b2fb3c18d06bd77d88ed9eb8784f8a4254712a83..b483deed311cf7a3111fd31aafd938a1aae1f9f7 100644 (file)
@@ -16,22 +16,20 @@ static int irqfixup __read_mostly;
 /*
  * Recovery handler for misrouted interrupts.
  */
-
 static int misrouted_irq(int irq, struct pt_regs *regs)
 {
        int i;
-       irq_desc_t *desc;
        int ok = 0;
        int work = 0;   /* Did we do work for a real IRQ */
 
-       for(i = 1; i < NR_IRQS; i++) {
+       for (i = 1; i < NR_IRQS; i++) {
+               struct irq_desc *desc = irq_desc + i;
                struct irqaction *action;
 
                if (i == irq)   /* Already tried */
                        continue;
-               desc = &irq_desc[i];
+
                spin_lock(&desc->lock);
-               action = desc->action;
                /* Already running on another processor */
                if (desc->status & IRQ_INPROGRESS) {
                        /*
@@ -45,7 +43,9 @@ static int misrouted_irq(int irq, struct pt_regs *regs)
                }
                /* Honour the normal IRQ locking */
                desc->status |= IRQ_INPROGRESS;
+               action = desc->action;
                spin_unlock(&desc->lock);
+
                while (action) {
                        /* Only shared IRQ handlers are safe to call */
                        if (action->flags & SA_SHIRQ) {
@@ -62,9 +62,8 @@ static int misrouted_irq(int irq, struct pt_regs *regs)
 
                /*
                 * While we were looking for a fixup someone queued a real
-                * IRQ clashing with our walk
+                * IRQ clashing with our walk:
                 */
-
                while ((desc->status & IRQ_PENDING) && action) {
                        /*
                         * Perform real IRQ processing for the IRQ we deferred
@@ -80,8 +79,8 @@ static int misrouted_irq(int irq, struct pt_regs *regs)
                 * If we did actual work for the real IRQ line we must let the
                 * IRQ controller clean up too
                 */
-               if(work)
-                       desc->handler->end(i);
+               if (work && desc->chip && desc->chip->end)
+                       desc->chip->end(i);
                spin_unlock(&desc->lock);
        }
        /* So the caller can adjust the irq error counts */
@@ -100,7 +99,8 @@ static int misrouted_irq(int irq, struct pt_regs *regs)
  */
 
 static void
-__report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+__report_bad_irq(unsigned int irq, struct irq_desc *desc,
+                irqreturn_t action_ret)
 {
        struct irqaction *action;
 
@@ -113,6 +113,7 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
        }
        dump_stack();
        printk(KERN_ERR "handlers:\n");
+
        action = desc->action;
        while (action) {
                printk(KERN_ERR "[<%p>]", action->handler);
@@ -123,7 +124,8 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
        }
 }
 
-static void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+static void
+report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
 {
        static int count = 100;
 
@@ -133,8 +135,8 @@ static void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t actio
        }
 }
 
-void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret,
-                       struct pt_regs *regs)
+void note_interrupt(unsigned int irq, struct irq_desc *desc,
+                   irqreturn_t action_ret, struct pt_regs *regs)
 {
        if (unlikely(action_ret != IRQ_HANDLED)) {
                desc->irqs_unhandled++;
@@ -166,7 +168,8 @@ void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret,
                 */
                printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
                desc->status |= IRQ_DISABLED;
-               desc->handler->disable(irq);
+               desc->depth = 1;
+               desc->chip->disable(irq);
        }
        desc->irqs_unhandled = 0;
 }
@@ -177,6 +180,7 @@ int __init noirqdebug_setup(char *str)
 {
        noirqdebug = 1;
        printk(KERN_INFO "IRQ lockup detection disabled\n");
+
        return 1;
 }
 
@@ -187,6 +191,7 @@ static int __init irqfixup_setup(char *str)
        irqfixup = 1;
        printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n");
        printk(KERN_WARNING "This may impact system performance.\n");
+
        return 1;
 }
 
index 58f0f382597cf4416e475c63c2fa3736462de7f2..50087ecf337ea17e5429188688187b6623a57f20 100644 (file)
@@ -1042,7 +1042,6 @@ asmlinkage long compat_sys_kexec_load(unsigned long entry,
 
 void crash_kexec(struct pt_regs *regs)
 {
-       struct kimage *image;
        int locked;
 
 
@@ -1056,12 +1055,11 @@ void crash_kexec(struct pt_regs *regs)
         */
        locked = xchg(&kexec_lock, 1);
        if (!locked) {
-               image = xchg(&kexec_crash_image, NULL);
-               if (image) {
+               if (kexec_crash_image) {
                        struct pt_regs fixed_regs;
                        crash_setup_regs(&fixed_regs, regs);
                        machine_crash_shutdown(&fixed_regs);
-                       machine_kexec(image);
+                       machine_kexec(kexec_crash_image);
                }
                xchg(&kexec_lock, 0);
        }
index 10e5b872adf6f56d2755976dee65a6e8a9a6ab8a..99c022ac3d21c7105e5d37fdc288e0dc7527d8a8 100644 (file)
@@ -1,4 +1,4 @@
-/* Rewritten by Rusty Russell, on the backs of many others...
+/*
    Copyright (C) 2002 Richard Henderson
    Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
 
@@ -122,9 +122,17 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
 extern const struct kernel_symbol __start___ksymtab_gpl_future[];
 extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
+extern const struct kernel_symbol __start___ksymtab_unused[];
+extern const struct kernel_symbol __stop___ksymtab_unused[];
+extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
+extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
+extern const struct kernel_symbol __start___ksymtab_gpl_future[];
+extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
 extern const unsigned long __start___kcrctab[];
 extern const unsigned long __start___kcrctab_gpl[];
 extern const unsigned long __start___kcrctab_gpl_future[];
+extern const unsigned long __start___kcrctab_unused[];
+extern const unsigned long __start___kcrctab_unused_gpl[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -144,6 +152,17 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
        return NULL;
 }
 
+static void printk_unused_warning(const char *name)
+{
+       printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
+               "however this module is using it.\n", name);
+       printk(KERN_WARNING "This symbol will go away in the future.\n");
+       printk(KERN_WARNING "Please evalute if this is the right api to use, "
+               "and if it really is, submit a report the linux kernel "
+               "mailinglist together with submitting your code for "
+               "inclusion.\n");
+}
+
 /* Find a symbol, return value, crc and module which owns it */
 static unsigned long __find_symbol(const char *name,
                                   struct module **owner,
@@ -186,6 +205,25 @@ static unsigned long __find_symbol(const char *name,
                return ks->value;
        }
 
+       ks = lookup_symbol(name, __start___ksymtab_unused,
+                                __stop___ksymtab_unused);
+       if (ks) {
+               printk_unused_warning(name);
+               *crc = symversion(__start___kcrctab_unused,
+                                 (ks - __start___ksymtab_unused));
+               return ks->value;
+       }
+
+       if (gplok)
+               ks = lookup_symbol(name, __start___ksymtab_unused_gpl,
+                                __stop___ksymtab_unused_gpl);
+       if (ks) {
+               printk_unused_warning(name);
+               *crc = symversion(__start___kcrctab_unused_gpl,
+                                 (ks - __start___ksymtab_unused_gpl));
+               return ks->value;
+       }
+
        /* Now try modules. */ 
        list_for_each_entry(mod, &modules, list) {
                *owner = mod;
@@ -204,6 +242,23 @@ static unsigned long __find_symbol(const char *name,
                                return ks->value;
                        }
                }
+               ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms);
+               if (ks) {
+                       printk_unused_warning(name);
+                       *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms));
+                       return ks->value;
+               }
+
+               if (gplok) {
+                       ks = lookup_symbol(name, mod->unused_gpl_syms,
+                                          mod->unused_gpl_syms + mod->num_unused_gpl_syms);
+                       if (ks) {
+                               printk_unused_warning(name);
+                               *crc = symversion(mod->unused_gpl_crcs,
+                                                 (ks - mod->unused_gpl_syms));
+                               return ks->value;
+                       }
+               }
                ks = lookup_symbol(name, mod->gpl_future_syms,
                                   (mod->gpl_future_syms +
                                    mod->num_gpl_future_syms));
@@ -1403,10 +1458,27 @@ static struct module *load_module(void __user *umod,
        Elf_Ehdr *hdr;
        Elf_Shdr *sechdrs;
        char *secstrings, *args, *modmagic, *strtab = NULL;
-       unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
-               exportindex, modindex, obsparmindex, infoindex, gplindex,
-               crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
-               gplfuturecrcindex, unwindex = 0;
+       unsigned int i;
+       unsigned int symindex = 0;
+       unsigned int strindex = 0;
+       unsigned int setupindex;
+       unsigned int exindex;
+       unsigned int exportindex;
+       unsigned int modindex;
+       unsigned int obsparmindex;
+       unsigned int infoindex;
+       unsigned int gplindex;
+       unsigned int crcindex;
+       unsigned int gplcrcindex;
+       unsigned int versindex;
+       unsigned int pcpuindex;
+       unsigned int gplfutureindex;
+       unsigned int gplfuturecrcindex;
+       unsigned int unwindex = 0;
+       unsigned int unusedindex;
+       unsigned int unusedcrcindex;
+       unsigned int unusedgplindex;
+       unsigned int unusedgplcrcindex;
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1487,9 +1559,13 @@ static struct module *load_module(void __user *umod,
        exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
        gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
        gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
+       unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused");
+       unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl");
        crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
        gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
        gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
+       unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused");
+       unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl");
        setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
        exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
        obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
@@ -1638,14 +1714,27 @@ static struct module *load_module(void __user *umod,
                mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
        mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
                                        sizeof(*mod->gpl_future_syms);
+       mod->num_unused_syms = sechdrs[unusedindex].sh_size /
+                                       sizeof(*mod->unused_syms);
+       mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size /
+                                       sizeof(*mod->unused_gpl_syms);
        mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
        if (gplfuturecrcindex)
                mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
 
+       mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
+       if (unusedcrcindex)
+               mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;
+       mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;
+       if (unusedgplcrcindex)
+               mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr;
+
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !crcindex) || 
            (mod->num_gpl_syms && !gplcrcindex) ||
-           (mod->num_gpl_future_syms && !gplfuturecrcindex)) {
+           (mod->num_gpl_future_syms && !gplfuturecrcindex) ||
+           (mod->num_unused_syms && !unusedcrcindex) ||
+           (mod->num_unused_gpl_syms && !unusedgplcrcindex)) {
                printk(KERN_WARNING "%s: No versions for exported symbols."
                       " Tainting kernel.\n", mod->name);
                add_taint(TAINT_FORCED_MODULE);
index 036b6285b15ccb195848a64e03fa741fd20e8d89..e38e4bac97cac6dde3cacd552f189ef77882bb62 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/poison.h>
 #include <linux/spinlock.h>
 #include <linux/kallsyms.h>
 #include <linux/interrupt.h>
@@ -381,7 +382,7 @@ void debug_mutex_set_owner(struct mutex *lock,
 
 void debug_mutex_init_waiter(struct mutex_waiter *waiter)
 {
-       memset(waiter, 0x11, sizeof(*waiter));
+       memset(waiter, MUTEX_DEBUG_INIT, sizeof(*waiter));
        waiter->magic = waiter;
        INIT_LIST_HEAD(&waiter->list);
 }
@@ -397,7 +398,7 @@ void debug_mutex_wake_waiter(struct mutex *lock, struct mutex_waiter *waiter)
 void debug_mutex_free_waiter(struct mutex_waiter *waiter)
 {
        DEBUG_WARN_ON(!list_empty(&waiter->list));
-       memset(waiter, 0x22, sizeof(*waiter));
+       memset(waiter, MUTEX_DEBUG_FREE, sizeof(*waiter));
 }
 
 void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
index fc311a4673a25e451e94c1eef38c00bc425acf5a..857b4fa091244758b5fc0976cf44d58f914f20ec 100644 (file)
@@ -38,13 +38,22 @@ config PM_DEBUG
 
 config PM_TRACE
        bool "Suspend/resume event tracing"
-       depends on PM && PM_DEBUG && X86_32
-       default y
+       depends on PM && PM_DEBUG && X86_32 && EXPERIMENTAL
+       default n
        ---help---
        This enables some cheesy code to save the last PM event point in the
        RTC across reboots, so that you can debug a machine that just hangs
        during suspend (or more commonly, during resume).
 
+       To use this debugging feature you should attempt to suspend the machine,
+       then reboot it, then run
+
+               dmesg -s 1000000 | grep 'hash matches'
+
+       CAUTION: this option will cause your machine's real-time clock to be
+       set to an invalid time after a resume.
+
+
 config SOFTWARE_SUSPEND
        bool "Software Suspend"
        depends on PM && SWAP && (X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP)
index 68afe121e5071f0574e37e7b9e20f1d66bd4c290..5a730fdb1a2cecf6b10c2112ba777fbb5fb7c794 100644 (file)
@@ -299,7 +299,7 @@ out:
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static int profile_cpu_callback(struct notifier_block *info,
+static int __devinit profile_cpu_callback(struct notifier_block *info,
                                        unsigned long action, void *__cpu)
 {
        int node, cpu = (unsigned long)__cpu;
index 20e9710fc21c5fa5bc3d6c88342f8ba1dc4f5f0b..f464f5ae3f11a8edfe12d7ff83b609013526cfe6 100644 (file)
@@ -182,6 +182,15 @@ long rcu_batches_completed(void)
        return rcu_ctrlblk.completed;
 }
 
+/*
+ * Return the number of RCU batches processed thus far.  Useful
+ * for debug and statistics.
+ */
+long rcu_batches_completed_bh(void)
+{
+       return rcu_bh_ctrlblk.completed;
+}
+
 static void rcu_barrier_callback(struct rcu_head *notused)
 {
        if (atomic_dec_and_test(&rcu_barrier_cpu_count))
@@ -539,7 +548,7 @@ static void __devinit rcu_online_cpu(int cpu)
        tasklet_init(&per_cpu(rcu_tasklet, cpu), rcu_process_callbacks, 0UL);
 }
 
-static int rcu_cpu_notify(struct notifier_block *self,
+static int __devinit rcu_cpu_notify(struct notifier_block *self,
                                unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
@@ -556,7 +565,7 @@ static int rcu_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block rcu_nb = {
+static struct notifier_block __devinitdata rcu_nb = {
        .notifier_call  = rcu_cpu_notify,
 };
 
@@ -619,6 +628,7 @@ module_param(qlowmark, int, 0);
 module_param(rsinterval, int, 0);
 #endif
 EXPORT_SYMBOL_GPL(rcu_batches_completed);
+EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
 EXPORT_SYMBOL_GPL(call_rcu);
 EXPORT_SYMBOL_GPL(call_rcu_bh);
 EXPORT_SYMBOL_GPL(synchronize_rcu);
index 8154e7589d1284a7f96b1aa3b587ab2ffc01c299..4d1c3d2471278ebe93e00d7291eb253e83f7d89a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Read-Copy Update /proc-based torture test facility
+ * Read-Copy Update module-based torture test facility
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -53,6 +53,7 @@ static int stat_interval;     /* Interval between stats, in seconds. */
 static int verbose;            /* Print more debug info. */
 static int test_no_idle_hz;    /* Test RCU's support for tickless idle CPUs. */
 static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
+static char *torture_type = "rcu"; /* What to torture. */
 
 module_param(nreaders, int, 0);
 MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
@@ -64,13 +65,16 @@ module_param(test_no_idle_hz, bool, 0);
 MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
 module_param(shuffle_interval, int, 0);
 MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
-#define TORTURE_FLAG "rcutorture: "
+module_param(torture_type, charp, 0);
+MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh)");
+
+#define TORTURE_FLAG "-torture:"
 #define PRINTK_STRING(s) \
-       do { printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0)
+       do { printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0)
 #define VERBOSE_PRINTK_STRING(s) \
-       do { if (verbose) printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0)
+       do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0)
 #define VERBOSE_PRINTK_ERRSTRING(s) \
-       do { if (verbose) printk(KERN_ALERT TORTURE_FLAG "!!! " s "\n"); } while (0)
+       do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0)
 
 static char printk_buf[4096];
 
@@ -139,28 +143,6 @@ rcu_torture_free(struct rcu_torture *p)
        spin_unlock_bh(&rcu_torture_lock);
 }
 
-static void
-rcu_torture_cb(struct rcu_head *p)
-{
-       int i;
-       struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu);
-
-       if (fullstop) {
-               /* Test is ending, just drop callbacks on the floor. */
-               /* The next initialization will pick up the pieces. */
-               return;
-       }
-       i = rp->rtort_pipe_count;
-       if (i > RCU_TORTURE_PIPE_LEN)
-               i = RCU_TORTURE_PIPE_LEN;
-       atomic_inc(&rcu_torture_wcount[i]);
-       if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
-               rp->rtort_mbtest = 0;
-               rcu_torture_free(rp);
-       } else
-               call_rcu(p, rcu_torture_cb);
-}
-
 struct rcu_random_state {
        unsigned long rrs_state;
        unsigned long rrs_count;
@@ -190,6 +172,119 @@ rcu_random(struct rcu_random_state *rrsp)
        return swahw32(rrsp->rrs_state);
 }
 
+/*
+ * Operations vector for selecting different types of tests.
+ */
+
+struct rcu_torture_ops {
+       void (*init)(void);
+       void (*cleanup)(void);
+       int (*readlock)(void);
+       void (*readunlock)(int idx);
+       int (*completed)(void);
+       void (*deferredfree)(struct rcu_torture *p);
+       int (*stats)(char *page);
+       char *name;
+};
+static struct rcu_torture_ops *cur_ops = NULL;
+
+/*
+ * Definitions for rcu torture testing.
+ */
+
+static int rcu_torture_read_lock(void)
+{
+       rcu_read_lock();
+       return 0;
+}
+
+static void rcu_torture_read_unlock(int idx)
+{
+       rcu_read_unlock();
+}
+
+static int rcu_torture_completed(void)
+{
+       return rcu_batches_completed();
+}
+
+static void
+rcu_torture_cb(struct rcu_head *p)
+{
+       int i;
+       struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu);
+
+       if (fullstop) {
+               /* Test is ending, just drop callbacks on the floor. */
+               /* The next initialization will pick up the pieces. */
+               return;
+       }
+       i = rp->rtort_pipe_count;
+       if (i > RCU_TORTURE_PIPE_LEN)
+               i = RCU_TORTURE_PIPE_LEN;
+       atomic_inc(&rcu_torture_wcount[i]);
+       if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
+               rp->rtort_mbtest = 0;
+               rcu_torture_free(rp);
+       } else
+               cur_ops->deferredfree(rp);
+}
+
+static void rcu_torture_deferred_free(struct rcu_torture *p)
+{
+       call_rcu(&p->rtort_rcu, rcu_torture_cb);
+}
+
+static struct rcu_torture_ops rcu_ops = {
+       .init = NULL,
+       .cleanup = NULL,
+       .readlock = rcu_torture_read_lock,
+       .readunlock = rcu_torture_read_unlock,
+       .completed = rcu_torture_completed,
+       .deferredfree = rcu_torture_deferred_free,
+       .stats = NULL,
+       .name = "rcu"
+};
+
+/*
+ * Definitions for rcu_bh torture testing.
+ */
+
+static int rcu_bh_torture_read_lock(void)
+{
+       rcu_read_lock_bh();
+       return 0;
+}
+
+static void rcu_bh_torture_read_unlock(int idx)
+{
+       rcu_read_unlock_bh();
+}
+
+static int rcu_bh_torture_completed(void)
+{
+       return rcu_batches_completed_bh();
+}
+
+static void rcu_bh_torture_deferred_free(struct rcu_torture *p)
+{
+       call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
+}
+
+static struct rcu_torture_ops rcu_bh_ops = {
+       .init = NULL,
+       .cleanup = NULL,
+       .readlock = rcu_bh_torture_read_lock,
+       .readunlock = rcu_bh_torture_read_unlock,
+       .completed = rcu_bh_torture_completed,
+       .deferredfree = rcu_bh_torture_deferred_free,
+       .stats = NULL,
+       .name = "rcu_bh"
+};
+
+static struct rcu_torture_ops *torture_ops[] =
+       { &rcu_ops, &rcu_bh_ops, NULL };
+
 /*
  * RCU torture writer kthread.  Repeatedly substitutes a new structure
  * for that pointed to by rcu_torture_current, freeing the old structure
@@ -209,8 +304,6 @@ rcu_torture_writer(void *arg)
 
        do {
                schedule_timeout_uninterruptible(1);
-               if (rcu_batches_completed() == oldbatch)
-                       continue;
                if ((rp = rcu_torture_alloc()) == NULL)
                        continue;
                rp->rtort_pipe_count = 0;
@@ -225,10 +318,10 @@ rcu_torture_writer(void *arg)
                                i = RCU_TORTURE_PIPE_LEN;
                        atomic_inc(&rcu_torture_wcount[i]);
                        old_rp->rtort_pipe_count++;
-                       call_rcu(&old_rp->rtort_rcu, rcu_torture_cb);
+                       cur_ops->deferredfree(old_rp);
                }
                rcu_torture_current_version++;
-               oldbatch = rcu_batches_completed();
+               oldbatch = cur_ops->completed();
        } while (!kthread_should_stop() && !fullstop);
        VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
        while (!kthread_should_stop())
@@ -246,6 +339,7 @@ static int
 rcu_torture_reader(void *arg)
 {
        int completed;
+       int idx;
        DEFINE_RCU_RANDOM(rand);
        struct rcu_torture *p;
        int pipe_count;
@@ -254,12 +348,12 @@ rcu_torture_reader(void *arg)
        set_user_nice(current, 19);
 
        do {
-               rcu_read_lock();
-               completed = rcu_batches_completed();
+               idx = cur_ops->readlock();
+               completed = cur_ops->completed();
                p = rcu_dereference(rcu_torture_current);
                if (p == NULL) {
                        /* Wait for rcu_torture_writer to get underway */
-                       rcu_read_unlock();
+                       cur_ops->readunlock(idx);
                        schedule_timeout_interruptible(HZ);
                        continue;
                }
@@ -273,14 +367,14 @@ rcu_torture_reader(void *arg)
                        pipe_count = RCU_TORTURE_PIPE_LEN;
                }
                ++__get_cpu_var(rcu_torture_count)[pipe_count];
-               completed = rcu_batches_completed() - completed;
+               completed = cur_ops->completed() - completed;
                if (completed > RCU_TORTURE_PIPE_LEN) {
                        /* Should not happen, but... */
                        completed = RCU_TORTURE_PIPE_LEN;
                }
                ++__get_cpu_var(rcu_torture_batch)[completed];
                preempt_enable();
-               rcu_read_unlock();
+               cur_ops->readunlock(idx);
                schedule();
        } while (!kthread_should_stop() && !fullstop);
        VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
@@ -311,7 +405,7 @@ rcu_torture_printk(char *page)
                if (pipesummary[i] != 0)
                        break;
        }
-       cnt += sprintf(&page[cnt], "rcutorture: ");
+       cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
        cnt += sprintf(&page[cnt],
                       "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d "
                       "rtmbe: %d",
@@ -324,7 +418,7 @@ rcu_torture_printk(char *page)
                       atomic_read(&n_rcu_torture_mberror));
        if (atomic_read(&n_rcu_torture_mberror) != 0)
                cnt += sprintf(&page[cnt], " !!!");
-       cnt += sprintf(&page[cnt], "\nrcutorture: ");
+       cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
        if (i > 1) {
                cnt += sprintf(&page[cnt], "!!! ");
                atomic_inc(&n_rcu_torture_error);
@@ -332,17 +426,19 @@ rcu_torture_printk(char *page)
        cnt += sprintf(&page[cnt], "Reader Pipe: ");
        for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
                cnt += sprintf(&page[cnt], " %ld", pipesummary[i]);
-       cnt += sprintf(&page[cnt], "\nrcutorture: ");
+       cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
        cnt += sprintf(&page[cnt], "Reader Batch: ");
-       for (i = 0; i < RCU_TORTURE_PIPE_LEN; i++)
+       for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
                cnt += sprintf(&page[cnt], " %ld", batchsummary[i]);
-       cnt += sprintf(&page[cnt], "\nrcutorture: ");
+       cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
        cnt += sprintf(&page[cnt], "Free-Block Circulation: ");
        for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
                cnt += sprintf(&page[cnt], " %d",
                               atomic_read(&rcu_torture_wcount[i]));
        }
        cnt += sprintf(&page[cnt], "\n");
+       if (cur_ops->stats != NULL)
+               cnt += cur_ops->stats(&page[cnt]);
        return cnt;
 }
 
@@ -444,11 +540,11 @@ rcu_torture_shuffle(void *arg)
 static inline void
 rcu_torture_print_module_parms(char *tag)
 {
-       printk(KERN_ALERT TORTURE_FLAG "--- %s: nreaders=%d "
+       printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d "
                "stat_interval=%d verbose=%d test_no_idle_hz=%d "
                "shuffle_interval = %d\n",
-               tag, nrealreaders, stat_interval, verbose, test_no_idle_hz,
-               shuffle_interval);
+               torture_type, tag, nrealreaders, stat_interval, verbose,
+               test_no_idle_hz, shuffle_interval);
 }
 
 static void
@@ -493,6 +589,9 @@ rcu_torture_cleanup(void)
        rcu_barrier();
 
        rcu_torture_stats_print();  /* -After- the stats thread is stopped! */
+
+       if (cur_ops->cleanup != NULL)
+               cur_ops->cleanup();
        if (atomic_read(&n_rcu_torture_error))
                rcu_torture_print_module_parms("End of test: FAILURE");
        else
@@ -508,6 +607,20 @@ rcu_torture_init(void)
 
        /* Process args and tell the world that the torturer is on the job. */
 
+       for (i = 0; cur_ops = torture_ops[i], cur_ops != NULL; i++) {
+               cur_ops = torture_ops[i];
+               if (strcmp(torture_type, cur_ops->name) == 0) {
+                       break;
+               }
+       }
+       if (cur_ops == NULL) {
+               printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n",
+                      torture_type);
+               return (-EINVAL);
+       }
+       if (cur_ops->init != NULL)
+               cur_ops->init(); /* no "goto unwind" prior to this point!!! */
+
        if (nreaders >= 0)
                nrealreaders = nreaders;
        else
index e3080fcc66a3b1237e30326782eed2a8fd184323..bf1130d81b7f09d35c81e436592b407e56c526d3 100644 (file)
 
 struct resource ioport_resource = {
        .name   = "PCI IO",
-       .start  = 0x0000,
+       .start  = 0,
        .end    = IO_SPACE_LIMIT,
        .flags  = IORESOURCE_IO,
 };
-
 EXPORT_SYMBOL(ioport_resource);
 
 struct resource iomem_resource = {
        .name   = "PCI mem",
-       .start  = 0UL,
-       .end    = ~0UL,
+       .start  = 0,
+       .end    = -1,
        .flags  = IORESOURCE_MEM,
 };
-
 EXPORT_SYMBOL(iomem_resource);
 
 static DEFINE_RWLOCK(resource_lock);
@@ -83,10 +81,10 @@ static int r_show(struct seq_file *m, void *v)
        for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent)
                if (p->parent == root)
                        break;
-       seq_printf(m, "%*s%0*lx-%0*lx : %s\n",
+       seq_printf(m, "%*s%0*llx-%0*llx : %s\n",
                        depth * 2, "",
-                       width, r->start,
-                       width, r->end,
+                       width, (unsigned long long) r->start,
+                       width, (unsigned long long) r->end,
                        r->name ? r->name : "<BAD>");
        return 0;
 }
@@ -151,8 +149,8 @@ __initcall(ioresources_init);
 /* Return the conflict entry if you can't request it */
 static struct resource * __request_resource(struct resource *root, struct resource *new)
 {
-       unsigned long start = new->start;
-       unsigned long end = new->end;
+       resource_size_t start = new->start;
+       resource_size_t end = new->end;
        struct resource *tmp, **p;
 
        if (end < start)
@@ -232,15 +230,52 @@ int release_resource(struct resource *old)
 
 EXPORT_SYMBOL(release_resource);
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+/*
+ * Finds the lowest memory reosurce exists within [res->start.res->end)
+ * the caller must specify res->start, res->end, res->flags.
+ * If found, returns 0, res is overwritten, if not found, returns -1.
+ */
+int find_next_system_ram(struct resource *res)
+{
+       resource_size_t start, end;
+       struct resource *p;
+
+       BUG_ON(!res);
+
+       start = res->start;
+       end = res->end;
+
+       read_lock(&resource_lock);
+       for (p = iomem_resource.child; p ; p = p->sibling) {
+               /* system ram is just marked as IORESOURCE_MEM */
+               if (p->flags != res->flags)
+                       continue;
+               if (p->start > end) {
+                       p = NULL;
+                       break;
+               }
+               if (p->start >= start)
+                       break;
+       }
+       read_unlock(&resource_lock);
+       if (!p)
+               return -1;
+       /* copy data */
+       res->start = p->start;
+       res->end = p->end;
+       return 0;
+}
+#endif
+
 /*
  * Find empty slot in the resource tree given range and alignment.
  */
 static int find_resource(struct resource *root, struct resource *new,
-                        unsigned long size,
-                        unsigned long min, unsigned long max,
-                        unsigned long align,
+                        resource_size_t size, resource_size_t min,
+                        resource_size_t max, resource_size_t align,
                         void (*alignf)(void *, struct resource *,
-                                       unsigned long, unsigned long),
+                                       resource_size_t, resource_size_t),
                         void *alignf_data)
 {
        struct resource *this = root->child;
@@ -282,11 +317,10 @@ static int find_resource(struct resource *root, struct resource *new,
  * Allocate empty slot in the resource tree given range and alignment.
  */
 int allocate_resource(struct resource *root, struct resource *new,
-                     unsigned long size,
-                     unsigned long min, unsigned long max,
-                     unsigned long align,
+                     resource_size_t size, resource_size_t min,
+                     resource_size_t max, resource_size_t align,
                      void (*alignf)(void *, struct resource *,
-                                    unsigned long, unsigned long),
+                                    resource_size_t, resource_size_t),
                      void *alignf_data)
 {
        int err;
@@ -378,10 +412,10 @@ EXPORT_SYMBOL(insert_resource);
  * arguments.  Returns -EBUSY if it can't fit.  Existing children of
  * the resource are assumed to be immutable.
  */
-int adjust_resource(struct resource *res, unsigned long start, unsigned long size)
+int adjust_resource(struct resource *res, resource_size_t start, resource_size_t size)
 {
        struct resource *tmp, *parent = res->parent;
-       unsigned long end = start + size - 1;
+       resource_size_t end = start + size - 1;
        int result = -EBUSY;
 
        write_lock(&resource_lock);
@@ -428,7 +462,9 @@ EXPORT_SYMBOL(adjust_resource);
  *
  * Release-region releases a matching busy region.
  */
-struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
+struct resource * __request_region(struct resource *parent,
+                                  resource_size_t start, resource_size_t n,
+                                  const char *name)
 {
        struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
@@ -464,7 +500,8 @@ struct resource * __request_region(struct resource *parent, unsigned long start,
 
 EXPORT_SYMBOL(__request_region);
 
-int __check_region(struct resource *parent, unsigned long start, unsigned long n)
+int __check_region(struct resource *parent, resource_size_t start,
+                       resource_size_t n)
 {
        struct resource * res;
 
@@ -479,10 +516,11 @@ int __check_region(struct resource *parent, unsigned long start, unsigned long n
 
 EXPORT_SYMBOL(__check_region);
 
-void __release_region(struct resource *parent, unsigned long start, unsigned long n)
+void __release_region(struct resource *parent, resource_size_t start,
+                       resource_size_t n)
 {
        struct resource **p;
-       unsigned long end;
+       resource_size_t end;
 
        p = &parent->child;
        end = start + n - 1;
@@ -511,7 +549,9 @@ void __release_region(struct resource *parent, unsigned long start, unsigned lon
 
        write_unlock(&resource_lock);
 
-       printk(KERN_WARNING "Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
+       printk(KERN_WARNING "Trying to free nonexistent resource "
+               "<%016llx-%016llx>\n", (unsigned long long)start,
+               (unsigned long long)end);
 }
 
 EXPORT_SYMBOL(__release_region);
diff --git a/kernel/rtmutex-debug.c b/kernel/rtmutex-debug.c
new file mode 100644 (file)
index 0000000..4aa8a2c
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * RT-Mutexes: blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner:
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ * This code is based on the rt.c implementation in the preempt-rt tree.
+ * Portions of said code are
+ *
+ *  Copyright (C) 2004  LynuxWorks, Inc., Igor Manyilov, Bill Huey
+ *  Copyright (C) 2006  Esben Nielsen
+ *  Copyright (C) 2006  Kihon Technologies Inc.,
+ *                     Steven Rostedt <rostedt@goodmis.org>
+ *
+ * See rt.c in preempt-rt for proper credits and further information
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/kallsyms.h>
+#include <linux/syscalls.h>
+#include <linux/interrupt.h>
+#include <linux/plist.h>
+#include <linux/fs.h>
+
+#include "rtmutex_common.h"
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# include "rtmutex-debug.h"
+#else
+# include "rtmutex.h"
+#endif
+
+# define TRACE_WARN_ON(x)                      WARN_ON(x)
+# define TRACE_BUG_ON(x)                       BUG_ON(x)
+
+# define TRACE_OFF()                                           \
+do {                                                           \
+       if (rt_trace_on) {                                      \
+               rt_trace_on = 0;                                \
+               console_verbose();                              \
+               if (spin_is_locked(&current->pi_lock))          \
+                       spin_unlock(&current->pi_lock);         \
+               if (spin_is_locked(&current->held_list_lock))   \
+                       spin_unlock(&current->held_list_lock);  \
+       }                                                       \
+} while (0)
+
+# define TRACE_OFF_NOLOCK()                                    \
+do {                                                           \
+       if (rt_trace_on) {                                      \
+               rt_trace_on = 0;                                \
+               console_verbose();                              \
+       }                                                       \
+} while (0)
+
+# define TRACE_BUG_LOCKED()                    \
+do {                                           \
+       TRACE_OFF();                            \
+       BUG();                                  \
+} while (0)
+
+# define TRACE_WARN_ON_LOCKED(c)               \
+do {                                           \
+       if (unlikely(c)) {                      \
+               TRACE_OFF();                    \
+               WARN_ON(1);                     \
+       }                                       \
+} while (0)
+
+# define TRACE_BUG_ON_LOCKED(c)                        \
+do {                                           \
+       if (unlikely(c))                        \
+               TRACE_BUG_LOCKED();             \
+} while (0)
+
+#ifdef CONFIG_SMP
+# define SMP_TRACE_BUG_ON_LOCKED(c)    TRACE_BUG_ON_LOCKED(c)
+#else
+# define SMP_TRACE_BUG_ON_LOCKED(c)    do { } while (0)
+#endif
+
+/*
+ * deadlock detection flag. We turn it off when we detect
+ * the first problem because we dont want to recurse back
+ * into the tracing code when doing error printk or
+ * executing a BUG():
+ */
+int rt_trace_on = 1;
+
+void deadlock_trace_off(void)
+{
+       rt_trace_on = 0;
+}
+
+static void printk_task(task_t *p)
+{
+       if (p)
+               printk("%16s:%5d [%p, %3d]", p->comm, p->pid, p, p->prio);
+       else
+               printk("<none>");
+}
+
+static void printk_task_short(task_t *p)
+{
+       if (p)
+               printk("%s/%d [%p, %3d]", p->comm, p->pid, p, p->prio);
+       else
+               printk("<none>");
+}
+
+static void printk_lock(struct rt_mutex *lock, int print_owner)
+{
+       if (lock->name)
+               printk(" [%p] {%s}\n",
+                       lock, lock->name);
+       else
+               printk(" [%p] {%s:%d}\n",
+                       lock, lock->file, lock->line);
+
+       if (print_owner && rt_mutex_owner(lock)) {
+               printk(".. ->owner: %p\n", lock->owner);
+               printk(".. held by:  ");
+               printk_task(rt_mutex_owner(lock));
+               printk("\n");
+       }
+       if (rt_mutex_owner(lock)) {
+               printk("... acquired at:               ");
+               print_symbol("%s\n", lock->acquire_ip);
+       }
+}
+
+static void printk_waiter(struct rt_mutex_waiter *w)
+{
+       printk("-------------------------\n");
+       printk("| waiter struct %p:\n", w);
+       printk("| w->list_entry: [DP:%p/%p|SP:%p/%p|PRI:%d]\n",
+              w->list_entry.plist.prio_list.prev, w->list_entry.plist.prio_list.next,
+              w->list_entry.plist.node_list.prev, w->list_entry.plist.node_list.next,
+              w->list_entry.prio);
+       printk("| w->pi_list_entry: [DP:%p/%p|SP:%p/%p|PRI:%d]\n",
+              w->pi_list_entry.plist.prio_list.prev, w->pi_list_entry.plist.prio_list.next,
+              w->pi_list_entry.plist.node_list.prev, w->pi_list_entry.plist.node_list.next,
+              w->pi_list_entry.prio);
+       printk("\n| lock:\n");
+       printk_lock(w->lock, 1);
+       printk("| w->ti->task:\n");
+       printk_task(w->task);
+       printk("| blocked at:  ");
+       print_symbol("%s\n", w->ip);
+       printk("-------------------------\n");
+}
+
+static void show_task_locks(task_t *p)
+{
+       switch (p->state) {
+       case TASK_RUNNING:              printk("R"); break;
+       case TASK_INTERRUPTIBLE:        printk("S"); break;
+       case TASK_UNINTERRUPTIBLE:      printk("D"); break;
+       case TASK_STOPPED:              printk("T"); break;
+       case EXIT_ZOMBIE:               printk("Z"); break;
+       case EXIT_DEAD:                 printk("X"); break;
+       default:                        printk("?"); break;
+       }
+       printk_task(p);
+       if (p->pi_blocked_on) {
+               struct rt_mutex *lock = p->pi_blocked_on->lock;
+
+               printk(" blocked on:");
+               printk_lock(lock, 1);
+       } else
+               printk(" (not blocked)\n");
+}
+
+void rt_mutex_show_held_locks(task_t *task, int verbose)
+{
+       struct list_head *curr, *cursor = NULL;
+       struct rt_mutex *lock;
+       task_t *t;
+       unsigned long flags;
+       int count = 0;
+
+       if (!rt_trace_on)
+               return;
+
+       if (verbose) {
+               printk("------------------------------\n");
+               printk("| showing all locks held by: |  (");
+               printk_task_short(task);
+               printk("):\n");
+               printk("------------------------------\n");
+       }
+
+next:
+       spin_lock_irqsave(&task->held_list_lock, flags);
+       list_for_each(curr, &task->held_list_head) {
+               if (cursor && curr != cursor)
+                       continue;
+               lock = list_entry(curr, struct rt_mutex, held_list_entry);
+               t = rt_mutex_owner(lock);
+               WARN_ON(t != task);
+               count++;
+               cursor = curr->next;
+               spin_unlock_irqrestore(&task->held_list_lock, flags);
+
+               printk("\n#%03d:            ", count);
+               printk_lock(lock, 0);
+               goto next;
+       }
+       spin_unlock_irqrestore(&task->held_list_lock, flags);
+
+       printk("\n");
+}
+
+void rt_mutex_show_all_locks(void)
+{
+       task_t *g, *p;
+       int count = 10;
+       int unlock = 1;
+
+       printk("\n");
+       printk("----------------------\n");
+       printk("| showing all tasks: |\n");
+       printk("----------------------\n");
+
+       /*
+        * Here we try to get the tasklist_lock as hard as possible,
+        * if not successful after 2 seconds we ignore it (but keep
+        * trying). This is to enable a debug printout even if a
+        * tasklist_lock-holding task deadlocks or crashes.
+        */
+retry:
+       if (!read_trylock(&tasklist_lock)) {
+               if (count == 10)
+                       printk("hm, tasklist_lock locked, retrying... ");
+               if (count) {
+                       count--;
+                       printk(" #%d", 10-count);
+                       mdelay(200);
+                       goto retry;
+               }
+               printk(" ignoring it.\n");
+               unlock = 0;
+       }
+       if (count != 10)
+               printk(" locked it.\n");
+
+       do_each_thread(g, p) {
+               show_task_locks(p);
+               if (!unlock)
+                       if (read_trylock(&tasklist_lock))
+                               unlock = 1;
+       } while_each_thread(g, p);
+
+       printk("\n");
+
+       printk("-----------------------------------------\n");
+       printk("| showing all locks held in the system: |\n");
+       printk("-----------------------------------------\n");
+
+       do_each_thread(g, p) {
+               rt_mutex_show_held_locks(p, 0);
+               if (!unlock)
+                       if (read_trylock(&tasklist_lock))
+                               unlock = 1;
+       } while_each_thread(g, p);
+
+
+       printk("=============================================\n\n");
+
+       if (unlock)
+               read_unlock(&tasklist_lock);
+}
+
+void rt_mutex_debug_check_no_locks_held(task_t *task)
+{
+       struct rt_mutex_waiter *w;
+       struct list_head *curr;
+       struct rt_mutex *lock;
+
+       if (!rt_trace_on)
+               return;
+       if (!rt_prio(task->normal_prio) && rt_prio(task->prio)) {
+               printk("BUG: PI priority boost leaked!\n");
+               printk_task(task);
+               printk("\n");
+       }
+       if (list_empty(&task->held_list_head))
+               return;
+
+       spin_lock(&task->pi_lock);
+       plist_for_each_entry(w, &task->pi_waiters, pi_list_entry) {
+               TRACE_OFF();
+
+               printk("hm, PI interest held at exit time? Task:\n");
+               printk_task(task);
+               printk_waiter(w);
+               return;
+       }
+       spin_unlock(&task->pi_lock);
+
+       list_for_each(curr, &task->held_list_head) {
+               lock = list_entry(curr, struct rt_mutex, held_list_entry);
+
+               printk("BUG: %s/%d, lock held at task exit time!\n",
+                      task->comm, task->pid);
+               printk_lock(lock, 1);
+               if (rt_mutex_owner(lock) != task)
+                       printk("exiting task is not even the owner??\n");
+       }
+}
+
+int rt_mutex_debug_check_no_locks_freed(const void *from, unsigned long len)
+{
+       const void *to = from + len;
+       struct list_head *curr;
+       struct rt_mutex *lock;
+       unsigned long flags;
+       void *lock_addr;
+
+       if (!rt_trace_on)
+               return 0;
+
+       spin_lock_irqsave(&current->held_list_lock, flags);
+       list_for_each(curr, &current->held_list_head) {
+               lock = list_entry(curr, struct rt_mutex, held_list_entry);
+               lock_addr = lock;
+               if (lock_addr < from || lock_addr >= to)
+                       continue;
+               TRACE_OFF();
+
+               printk("BUG: %s/%d, active lock [%p(%p-%p)] freed!\n",
+                       current->comm, current->pid, lock, from, to);
+               dump_stack();
+               printk_lock(lock, 1);
+               if (rt_mutex_owner(lock) != current)
+                       printk("freeing task is not even the owner??\n");
+               return 1;
+       }
+       spin_unlock_irqrestore(&current->held_list_lock, flags);
+
+       return 0;
+}
+
+void rt_mutex_debug_task_free(struct task_struct *task)
+{
+       WARN_ON(!plist_head_empty(&task->pi_waiters));
+       WARN_ON(task->pi_blocked_on);
+}
+
+/*
+ * We fill out the fields in the waiter to store the information about
+ * the deadlock. We print when we return. act_waiter can be NULL in
+ * case of a remove waiter operation.
+ */
+void debug_rt_mutex_deadlock(int detect, struct rt_mutex_waiter *act_waiter,
+                            struct rt_mutex *lock)
+{
+       struct task_struct *task;
+
+       if (!rt_trace_on || detect || !act_waiter)
+               return;
+
+       task = rt_mutex_owner(act_waiter->lock);
+       if (task && task != current) {
+               act_waiter->deadlock_task_pid = task->pid;
+               act_waiter->deadlock_lock = lock;
+       }
+}
+
+void debug_rt_mutex_print_deadlock(struct rt_mutex_waiter *waiter)
+{
+       struct task_struct *task;
+
+       if (!waiter->deadlock_lock || !rt_trace_on)
+               return;
+
+       task = find_task_by_pid(waiter->deadlock_task_pid);
+       if (!task)
+               return;
+
+       TRACE_OFF_NOLOCK();
+
+       printk("\n============================================\n");
+       printk(  "[ BUG: circular locking deadlock detected! ]\n");
+       printk(  "--------------------------------------------\n");
+       printk("%s/%d is deadlocking current task %s/%d\n\n",
+              task->comm, task->pid, current->comm, current->pid);
+
+       printk("\n1) %s/%d is trying to acquire this lock:\n",
+              current->comm, current->pid);
+       printk_lock(waiter->lock, 1);
+
+       printk("... trying at:                 ");
+       print_symbol("%s\n", waiter->ip);
+
+       printk("\n2) %s/%d is blocked on this lock:\n", task->comm, task->pid);
+       printk_lock(waiter->deadlock_lock, 1);
+
+       rt_mutex_show_held_locks(current, 1);
+       rt_mutex_show_held_locks(task, 1);
+
+       printk("\n%s/%d's [blocked] stackdump:\n\n", task->comm, task->pid);
+       show_stack(task, NULL);
+       printk("\n%s/%d's [current] stackdump:\n\n",
+              current->comm, current->pid);
+       dump_stack();
+       rt_mutex_show_all_locks();
+       printk("[ turning off deadlock detection."
+              "Please report this trace. ]\n\n");
+       local_irq_disable();
+}
+
+void debug_rt_mutex_lock(struct rt_mutex *lock __IP_DECL__)
+{
+       unsigned long flags;
+
+       if (rt_trace_on) {
+               TRACE_WARN_ON_LOCKED(!list_empty(&lock->held_list_entry));
+
+               spin_lock_irqsave(&current->held_list_lock, flags);
+               list_add_tail(&lock->held_list_entry, &current->held_list_head);
+               spin_unlock_irqrestore(&current->held_list_lock, flags);
+
+               lock->acquire_ip = ip;
+       }
+}
+
+void debug_rt_mutex_unlock(struct rt_mutex *lock)
+{
+       unsigned long flags;
+
+       if (rt_trace_on) {
+               TRACE_WARN_ON_LOCKED(rt_mutex_owner(lock) != current);
+               TRACE_WARN_ON_LOCKED(list_empty(&lock->held_list_entry));
+
+               spin_lock_irqsave(&current->held_list_lock, flags);
+               list_del_init(&lock->held_list_entry);
+               spin_unlock_irqrestore(&current->held_list_lock, flags);
+       }
+}
+
+void debug_rt_mutex_proxy_lock(struct rt_mutex *lock,
+                              struct task_struct *powner __IP_DECL__)
+{
+       unsigned long flags;
+
+       if (rt_trace_on) {
+               TRACE_WARN_ON_LOCKED(!list_empty(&lock->held_list_entry));
+
+               spin_lock_irqsave(&powner->held_list_lock, flags);
+               list_add_tail(&lock->held_list_entry, &powner->held_list_head);
+               spin_unlock_irqrestore(&powner->held_list_lock, flags);
+
+               lock->acquire_ip = ip;
+       }
+}
+
+void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock)
+{
+       unsigned long flags;
+
+       if (rt_trace_on) {
+               struct task_struct *owner = rt_mutex_owner(lock);
+
+               TRACE_WARN_ON_LOCKED(!owner);
+               TRACE_WARN_ON_LOCKED(list_empty(&lock->held_list_entry));
+
+               spin_lock_irqsave(&owner->held_list_lock, flags);
+               list_del_init(&lock->held_list_entry);
+               spin_unlock_irqrestore(&owner->held_list_lock, flags);
+       }
+}
+
+void debug_rt_mutex_init_waiter(struct rt_mutex_waiter *waiter)
+{
+       memset(waiter, 0x11, sizeof(*waiter));
+       plist_node_init(&waiter->list_entry, MAX_PRIO);
+       plist_node_init(&waiter->pi_list_entry, MAX_PRIO);
+}
+
+void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter)
+{
+       TRACE_WARN_ON(!plist_node_empty(&waiter->list_entry));
+       TRACE_WARN_ON(!plist_node_empty(&waiter->pi_list_entry));
+       TRACE_WARN_ON(waiter->task);
+       memset(waiter, 0x22, sizeof(*waiter));
+}
+
+void debug_rt_mutex_init(struct rt_mutex *lock, const char *name)
+{
+       void *addr = lock;
+
+       if (rt_trace_on) {
+               rt_mutex_debug_check_no_locks_freed(addr,
+                                                   sizeof(struct rt_mutex));
+               INIT_LIST_HEAD(&lock->held_list_entry);
+               lock->name = name;
+       }
+}
+
+void rt_mutex_deadlock_account_lock(struct rt_mutex *lock, task_t *task)
+{
+}
+
+void rt_mutex_deadlock_account_unlock(struct task_struct *task)
+{
+}
+
diff --git a/kernel/rtmutex-debug.h b/kernel/rtmutex-debug.h
new file mode 100644 (file)
index 0000000..7612fbc
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * RT-Mutexes: blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner:
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ * This file contains macros used solely by rtmutex.c. Debug version.
+ */
+
+#define __IP_DECL__            , unsigned long ip
+#define __IP__                 , ip
+#define __RET_IP__             , (unsigned long)__builtin_return_address(0)
+
+extern void
+rt_mutex_deadlock_account_lock(struct rt_mutex *lock, struct task_struct *task);
+extern void rt_mutex_deadlock_account_unlock(struct task_struct *task);
+extern void debug_rt_mutex_init_waiter(struct rt_mutex_waiter *waiter);
+extern void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter);
+extern void debug_rt_mutex_init(struct rt_mutex *lock, const char *name);
+extern void debug_rt_mutex_lock(struct rt_mutex *lock __IP_DECL__);
+extern void debug_rt_mutex_unlock(struct rt_mutex *lock);
+extern void debug_rt_mutex_proxy_lock(struct rt_mutex *lock,
+                                     struct task_struct *powner __IP_DECL__);
+extern void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock);
+extern void debug_rt_mutex_deadlock(int detect, struct rt_mutex_waiter *waiter,
+                                   struct rt_mutex *lock);
+extern void debug_rt_mutex_print_deadlock(struct rt_mutex_waiter *waiter);
+# define debug_rt_mutex_reset_waiter(w)                        \
+       do { (w)->deadlock_lock = NULL; } while (0)
+
+static inline int debug_rt_mutex_detect_deadlock(struct rt_mutex_waiter *waiter,
+                                                int detect)
+{
+       return (waiter != NULL);
+}
diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c
new file mode 100644 (file)
index 0000000..e82c2f8
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * RT-Mutex-tester: scriptable tester for rt mutexes
+ *
+ * started by Thomas Gleixner:
+ *
+ *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ */
+#include <linux/config.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/sysdev.h>
+#include <linux/timer.h>
+
+#include "rtmutex.h"
+
+#define MAX_RT_TEST_THREADS    8
+#define MAX_RT_TEST_MUTEXES    8
+
+static spinlock_t rttest_lock;
+static atomic_t rttest_event;
+
+struct test_thread_data {
+       int                     opcode;
+       int                     opdata;
+       int                     mutexes[MAX_RT_TEST_MUTEXES];
+       int                     bkl;
+       int                     event;
+       struct sys_device       sysdev;
+};
+
+static struct test_thread_data thread_data[MAX_RT_TEST_THREADS];
+static task_t *threads[MAX_RT_TEST_THREADS];
+static struct rt_mutex mutexes[MAX_RT_TEST_MUTEXES];
+
+enum test_opcodes {
+       RTTEST_NOP = 0,
+       RTTEST_SCHEDOT,         /* 1 Sched other, data = nice */
+       RTTEST_SCHEDRT,         /* 2 Sched fifo, data = prio */
+       RTTEST_LOCK,            /* 3 Lock uninterruptible, data = lockindex */
+       RTTEST_LOCKNOWAIT,      /* 4 Lock uninterruptible no wait in wakeup, data = lockindex */
+       RTTEST_LOCKINT,         /* 5 Lock interruptible, data = lockindex */
+       RTTEST_LOCKINTNOWAIT,   /* 6 Lock interruptible no wait in wakeup, data = lockindex */
+       RTTEST_LOCKCONT,        /* 7 Continue locking after the wakeup delay */
+       RTTEST_UNLOCK,          /* 8 Unlock, data = lockindex */
+       RTTEST_LOCKBKL,         /* 9 Lock BKL */
+       RTTEST_UNLOCKBKL,       /* 10 Unlock BKL */
+       RTTEST_SIGNAL,          /* 11 Signal other test thread, data = thread id */
+       RTTEST_RESETEVENT = 98, /* 98 Reset event counter */
+       RTTEST_RESET = 99,      /* 99 Reset all pending operations */
+};
+
+static int handle_op(struct test_thread_data *td, int lockwakeup)
+{
+       int i, id, ret = -EINVAL;
+
+       switch(td->opcode) {
+
+       case RTTEST_NOP:
+               return 0;
+
+       case RTTEST_LOCKCONT:
+               td->mutexes[td->opdata] = 1;
+               td->event = atomic_add_return(1, &rttest_event);
+               return 0;
+
+       case RTTEST_RESET:
+               for (i = 0; i < MAX_RT_TEST_MUTEXES; i++) {
+                       if (td->mutexes[i] == 4) {
+                               rt_mutex_unlock(&mutexes[i]);
+                               td->mutexes[i] = 0;
+                       }
+               }
+
+               if (!lockwakeup && td->bkl == 4) {
+                       unlock_kernel();
+                       td->bkl = 0;
+               }
+               return 0;
+
+       case RTTEST_RESETEVENT:
+               atomic_set(&rttest_event, 0);
+               return 0;
+
+       default:
+               if (lockwakeup)
+                       return ret;
+       }
+
+       switch(td->opcode) {
+
+       case RTTEST_LOCK:
+       case RTTEST_LOCKNOWAIT:
+               id = td->opdata;
+               if (id < 0 || id >= MAX_RT_TEST_MUTEXES)
+                       return ret;
+
+               td->mutexes[id] = 1;
+               td->event = atomic_add_return(1, &rttest_event);
+               rt_mutex_lock(&mutexes[id]);
+               td->event = atomic_add_return(1, &rttest_event);
+               td->mutexes[id] = 4;
+               return 0;
+
+       case RTTEST_LOCKINT:
+       case RTTEST_LOCKINTNOWAIT:
+               id = td->opdata;
+               if (id < 0 || id >= MAX_RT_TEST_MUTEXES)
+                       return ret;
+
+               td->mutexes[id] = 1;
+               td->event = atomic_add_return(1, &rttest_event);
+               ret = rt_mutex_lock_interruptible(&mutexes[id], 0);
+               td->event = atomic_add_return(1, &rttest_event);
+               td->mutexes[id] = ret ? 0 : 4;
+               return ret ? -EINTR : 0;
+
+       case RTTEST_UNLOCK:
+               id = td->opdata;
+               if (id < 0 || id >= MAX_RT_TEST_MUTEXES || td->mutexes[id] != 4)
+                       return ret;
+
+               td->event = atomic_add_return(1, &rttest_event);
+               rt_mutex_unlock(&mutexes[id]);
+               td->event = atomic_add_return(1, &rttest_event);
+               td->mutexes[id] = 0;
+               return 0;
+
+       case RTTEST_LOCKBKL:
+               if (td->bkl)
+                       return 0;
+               td->bkl = 1;
+               lock_kernel();
+               td->bkl = 4;
+               return 0;
+
+       case RTTEST_UNLOCKBKL:
+               if (td->bkl != 4)
+                       break;
+               unlock_kernel();
+               td->bkl = 0;
+               return 0;
+
+       default:
+               break;
+       }
+       return ret;
+}
+
+/*
+ * Schedule replacement for rtsem_down(). Only called for threads with
+ * PF_MUTEX_TESTER set.
+ *
+ * This allows us to have finegrained control over the event flow.
+ *
+ */
+void schedule_rt_mutex_test(struct rt_mutex *mutex)
+{
+       int tid, op, dat;
+       struct test_thread_data *td;
+
+       /* We have to lookup the task */
+       for (tid = 0; tid < MAX_RT_TEST_THREADS; tid++) {
+               if (threads[tid] == current)
+                       break;
+       }
+
+       BUG_ON(tid == MAX_RT_TEST_THREADS);
+
+       td = &thread_data[tid];
+
+       op = td->opcode;
+       dat = td->opdata;
+
+       switch (op) {
+       case RTTEST_LOCK:
+       case RTTEST_LOCKINT:
+       case RTTEST_LOCKNOWAIT:
+       case RTTEST_LOCKINTNOWAIT:
+               if (mutex != &mutexes[dat])
+                       break;
+
+               if (td->mutexes[dat] != 1)
+                       break;
+
+               td->mutexes[dat] = 2;
+               td->event = atomic_add_return(1, &rttest_event);
+               break;
+
+       case RTTEST_LOCKBKL:
+       default:
+               break;
+       }
+
+       schedule();
+
+
+       switch (op) {
+       case RTTEST_LOCK:
+       case RTTEST_LOCKINT:
+               if (mutex != &mutexes[dat])
+                       return;
+
+               if (td->mutexes[dat] != 2)
+                       return;
+
+               td->mutexes[dat] = 3;
+               td->event = atomic_add_return(1, &rttest_event);
+               break;
+
+       case RTTEST_LOCKNOWAIT:
+       case RTTEST_LOCKINTNOWAIT:
+               if (mutex != &mutexes[dat])
+                       return;
+
+               if (td->mutexes[dat] != 2)
+                       return;
+
+               td->mutexes[dat] = 1;
+               td->event = atomic_add_return(1, &rttest_event);
+               return;
+
+       case RTTEST_LOCKBKL:
+               return;
+       default:
+               return;
+       }
+
+       td->opcode = 0;
+
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (td->opcode > 0) {
+                       int ret;
+
+                       set_current_state(TASK_RUNNING);
+                       ret = handle_op(td, 1);
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (td->opcode == RTTEST_LOCKCONT)
+                               break;
+                       td->opcode = ret;
+               }
+
+               /* Wait for the next command to be executed */
+               schedule();
+       }
+
+       /* Restore previous command and data */
+       td->opcode = op;
+       td->opdata = dat;
+}
+
+static int test_func(void *data)
+{
+       struct test_thread_data *td = data;
+       int ret;
+
+       current->flags |= PF_MUTEX_TESTER;
+       allow_signal(SIGHUP);
+
+       for(;;) {
+
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (td->opcode > 0) {
+                       set_current_state(TASK_RUNNING);
+                       ret = handle_op(td, 0);
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       td->opcode = ret;
+               }
+
+               /* Wait for the next command to be executed */
+               schedule();
+
+               if (signal_pending(current))
+                       flush_signals(current);
+
+               if(kthread_should_stop())
+                       break;
+       }
+       return 0;
+}
+
+/**
+ * sysfs_test_command - interface for test commands
+ * @dev:       thread reference
+ * @buf:       command for actual step
+ * @count:     length of buffer
+ *
+ * command syntax:
+ *
+ * opcode:data
+ */
+static ssize_t sysfs_test_command(struct sys_device *dev, const char *buf,
+                                 size_t count)
+{
+       struct sched_param schedpar;
+       struct test_thread_data *td;
+       char cmdbuf[32];
+       int op, dat, tid, ret;
+
+       td = container_of(dev, struct test_thread_data, sysdev);
+       tid = td->sysdev.id;
+
+       /* strings from sysfs write are not 0 terminated! */
+       if (count >= sizeof(cmdbuf))
+               return -EINVAL;
+
+       /* strip of \n: */
+       if (buf[count-1] == '\n')
+               count--;
+       if (count < 1)
+               return -EINVAL;
+
+       memcpy(cmdbuf, buf, count);
+       cmdbuf[count] = 0;
+
+       if (sscanf(cmdbuf, "%d:%d", &op, &dat) != 2)
+               return -EINVAL;
+
+       switch (op) {
+       case RTTEST_SCHEDOT:
+               schedpar.sched_priority = 0;
+               ret = sched_setscheduler(threads[tid], SCHED_NORMAL, &schedpar);
+               if (ret)
+                       return ret;
+               set_user_nice(current, 0);
+               break;
+
+       case RTTEST_SCHEDRT:
+               schedpar.sched_priority = dat;
+               ret = sched_setscheduler(threads[tid], SCHED_FIFO, &schedpar);
+               if (ret)
+                       return ret;
+               break;
+
+       case RTTEST_SIGNAL:
+               send_sig(SIGHUP, threads[tid], 0);
+               break;
+
+       default:
+               if (td->opcode > 0)
+                       return -EBUSY;
+               td->opdata = dat;
+               td->opcode = op;
+               wake_up_process(threads[tid]);
+       }
+
+       return count;
+}
+
+/**
+ * sysfs_test_status - sysfs interface for rt tester
+ * @dev:       thread to query
+ * @buf:       char buffer to be filled with thread status info
+ */
+static ssize_t sysfs_test_status(struct sys_device *dev, char *buf)
+{
+       struct test_thread_data *td;
+       char *curr = buf;
+       task_t *tsk;
+       int i;
+
+       td = container_of(dev, struct test_thread_data, sysdev);
+       tsk = threads[td->sysdev.id];
+
+       spin_lock(&rttest_lock);
+
+       curr += sprintf(curr,
+               "O: %4d, E:%8d, S: 0x%08lx, P: %4d, N: %4d, B: %p, K: %d, M:",
+               td->opcode, td->event, tsk->state,
+                       (MAX_RT_PRIO - 1) - tsk->prio,
+                       (MAX_RT_PRIO - 1) - tsk->normal_prio,
+               tsk->pi_blocked_on, td->bkl);
+
+       for (i = MAX_RT_TEST_MUTEXES - 1; i >=0 ; i--)
+               curr += sprintf(curr, "%d", td->mutexes[i]);
+
+       spin_unlock(&rttest_lock);
+
+       curr += sprintf(curr, ", T: %p, R: %p\n", tsk,
+                       mutexes[td->sysdev.id].owner);
+
+       return curr - buf;
+}
+
+static SYSDEV_ATTR(status, 0600, sysfs_test_status, NULL);
+static SYSDEV_ATTR(command, 0600, NULL, sysfs_test_command);
+
+static struct sysdev_class rttest_sysclass = {
+       set_kset_name("rttest"),
+};
+
+static int init_test_thread(int id)
+{
+       thread_data[id].sysdev.cls = &rttest_sysclass;
+       thread_data[id].sysdev.id = id;
+
+       threads[id] = kthread_run(test_func, &thread_data[id], "rt-test-%d", id);
+       if (IS_ERR(threads[id]))
+               return PTR_ERR(threads[id]);
+
+       return sysdev_register(&thread_data[id].sysdev);
+}
+
+static int init_rttest(void)
+{
+       int ret, i;
+
+       spin_lock_init(&rttest_lock);
+
+       for (i = 0; i < MAX_RT_TEST_MUTEXES; i++)
+               rt_mutex_init(&mutexes[i]);
+
+       ret = sysdev_class_register(&rttest_sysclass);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < MAX_RT_TEST_THREADS; i++) {
+               ret = init_test_thread(i);
+               if (ret)
+                       break;
+               ret = sysdev_create_file(&thread_data[i].sysdev, &attr_status);
+               if (ret)
+                       break;
+               ret = sysdev_create_file(&thread_data[i].sysdev, &attr_command);
+               if (ret)
+                       break;
+       }
+
+       printk("Initializing RT-Tester: %s\n", ret ? "Failed" : "OK" );
+
+       return ret;
+}
+
+device_initcall(init_rttest);
diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
new file mode 100644 (file)
index 0000000..45d6101
--- /dev/null
@@ -0,0 +1,990 @@
+/*
+ * RT-Mutexes: simple blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner.
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2005-2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *  Copyright (C) 2005 Kihon Technologies Inc., Steven Rostedt
+ *  Copyright (C) 2006 Esben Nielsen
+ */
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+#include "rtmutex_common.h"
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# include "rtmutex-debug.h"
+#else
+# include "rtmutex.h"
+#endif
+
+/*
+ * lock->owner state tracking:
+ *
+ * lock->owner holds the task_struct pointer of the owner. Bit 0 and 1
+ * are used to keep track of the "owner is pending" and "lock has
+ * waiters" state.
+ *
+ * owner       bit1    bit0
+ * NULL                0       0       lock is free (fast acquire possible)
+ * NULL                0       1       invalid state
+ * NULL                1       0       Transitional State*
+ * NULL                1       1       invalid state
+ * taskpointer 0       0       lock is held (fast release possible)
+ * taskpointer 0       1       task is pending owner
+ * taskpointer 1       0       lock is held and has waiters
+ * taskpointer 1       1       task is pending owner and lock has more waiters
+ *
+ * Pending ownership is assigned to the top (highest priority)
+ * waiter of the lock, when the lock is released. The thread is woken
+ * up and can now take the lock. Until the lock is taken (bit 0
+ * cleared) a competing higher priority thread can steal the lock
+ * which puts the woken up thread back on the waiters list.
+ *
+ * The fast atomic compare exchange based acquire and release is only
+ * possible when bit 0 and 1 of lock->owner are 0.
+ *
+ * (*) There's a small time where the owner can be NULL and the
+ * "lock has waiters" bit is set.  This can happen when grabbing the lock.
+ * To prevent a cmpxchg of the owner releasing the lock, we need to set this
+ * bit before looking at the lock, hence the reason this is a transitional
+ * state.
+ */
+
+static void
+rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner,
+                  unsigned long mask)
+{
+       unsigned long val = (unsigned long)owner | mask;
+
+       if (rt_mutex_has_waiters(lock))
+               val |= RT_MUTEX_HAS_WAITERS;
+
+       lock->owner = (struct task_struct *)val;
+}
+
+static inline void clear_rt_mutex_waiters(struct rt_mutex *lock)
+{
+       lock->owner = (struct task_struct *)
+                       ((unsigned long)lock->owner & ~RT_MUTEX_HAS_WAITERS);
+}
+
+static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
+{
+       if (!rt_mutex_has_waiters(lock))
+               clear_rt_mutex_waiters(lock);
+}
+
+/*
+ * We can speed up the acquire/release, if the architecture
+ * supports cmpxchg and if there's no debugging state to be set up
+ */
+#if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES)
+# define rt_mutex_cmpxchg(l,c,n)       (cmpxchg(&l->owner, c, n) == c)
+static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
+{
+       unsigned long owner, *p = (unsigned long *) &lock->owner;
+
+       do {
+               owner = *p;
+       } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner);
+}
+#else
+# define rt_mutex_cmpxchg(l,c,n)       (0)
+static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
+{
+       lock->owner = (struct task_struct *)
+                       ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS);
+}
+#endif
+
+/*
+ * Calculate task priority from the waiter list priority
+ *
+ * Return task->normal_prio when the waiter list is empty or when
+ * the waiter is not allowed to do priority boosting
+ */
+int rt_mutex_getprio(struct task_struct *task)
+{
+       if (likely(!task_has_pi_waiters(task)))
+               return task->normal_prio;
+
+       return min(task_top_pi_waiter(task)->pi_list_entry.prio,
+                  task->normal_prio);
+}
+
+/*
+ * Adjust the priority of a task, after its pi_waiters got modified.
+ *
+ * This can be both boosting and unboosting. task->pi_lock must be held.
+ */
+static void __rt_mutex_adjust_prio(struct task_struct *task)
+{
+       int prio = rt_mutex_getprio(task);
+
+       if (task->prio != prio)
+               rt_mutex_setprio(task, prio);
+}
+
+/*
+ * Adjust task priority (undo boosting). Called from the exit path of
+ * rt_mutex_slowunlock() and rt_mutex_slowlock().
+ *
+ * (Note: We do this outside of the protection of lock->wait_lock to
+ * allow the lock to be taken while or before we readjust the priority
+ * of task. We do not use the spin_xx_mutex() variants here as we are
+ * outside of the debug path.)
+ */
+static void rt_mutex_adjust_prio(struct task_struct *task)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&task->pi_lock, flags);
+       __rt_mutex_adjust_prio(task);
+       spin_unlock_irqrestore(&task->pi_lock, flags);
+}
+
+/*
+ * Max number of times we'll walk the boosting chain:
+ */
+int max_lock_depth = 1024;
+
+/*
+ * Adjust the priority chain. Also used for deadlock detection.
+ * Decreases task's usage by one - may thus free the task.
+ * Returns 0 or -EDEADLK.
+ */
+static int rt_mutex_adjust_prio_chain(task_t *task,
+                                     int deadlock_detect,
+                                     struct rt_mutex *orig_lock,
+                                     struct rt_mutex_waiter *orig_waiter,
+                                     struct task_struct *top_task
+                                     __IP_DECL__)
+{
+       struct rt_mutex *lock;
+       struct rt_mutex_waiter *waiter, *top_waiter = orig_waiter;
+       int detect_deadlock, ret = 0, depth = 0;
+       unsigned long flags;
+
+       detect_deadlock = debug_rt_mutex_detect_deadlock(orig_waiter,
+                                                        deadlock_detect);
+
+       /*
+        * The (de)boosting is a step by step approach with a lot of
+        * pitfalls. We want this to be preemptible and we want hold a
+        * maximum of two locks per step. So we have to check
+        * carefully whether things change under us.
+        */
+ again:
+       if (++depth > max_lock_depth) {
+               static int prev_max;
+
+               /*
+                * Print this only once. If the admin changes the limit,
+                * print a new message when reaching the limit again.
+                */
+               if (prev_max != max_lock_depth) {
+                       prev_max = max_lock_depth;
+                       printk(KERN_WARNING "Maximum lock depth %d reached "
+                              "task: %s (%d)\n", max_lock_depth,
+                              top_task->comm, top_task->pid);
+               }
+               put_task_struct(task);
+
+               return deadlock_detect ? -EDEADLK : 0;
+       }
+ retry:
+       /*
+        * Task can not go away as we did a get_task() before !
+        */
+       spin_lock_irqsave(&task->pi_lock, flags);
+
+       waiter = task->pi_blocked_on;
+       /*
+        * Check whether the end of the boosting chain has been
+        * reached or the state of the chain has changed while we
+        * dropped the locks.
+        */
+       if (!waiter || !waiter->task)
+               goto out_unlock_pi;
+
+       if (top_waiter && (!task_has_pi_waiters(task) ||
+                          top_waiter != task_top_pi_waiter(task)))
+               goto out_unlock_pi;
+
+       /*
+        * When deadlock detection is off then we check, if further
+        * priority adjustment is necessary.
+        */
+       if (!detect_deadlock && waiter->list_entry.prio == task->prio)
+               goto out_unlock_pi;
+
+       lock = waiter->lock;
+       if (!spin_trylock(&lock->wait_lock)) {
+               spin_unlock_irqrestore(&task->pi_lock, flags);
+               cpu_relax();
+               goto retry;
+       }
+
+       /* Deadlock detection */
+       if (lock == orig_lock || rt_mutex_owner(lock) == top_task) {
+               debug_rt_mutex_deadlock(deadlock_detect, orig_waiter, lock);
+               spin_unlock(&lock->wait_lock);
+               ret = deadlock_detect ? -EDEADLK : 0;
+               goto out_unlock_pi;
+       }
+
+       top_waiter = rt_mutex_top_waiter(lock);
+
+       /* Requeue the waiter */
+       plist_del(&waiter->list_entry, &lock->wait_list);
+       waiter->list_entry.prio = task->prio;
+       plist_add(&waiter->list_entry, &lock->wait_list);
+
+       /* Release the task */
+       spin_unlock_irqrestore(&task->pi_lock, flags);
+       put_task_struct(task);
+
+       /* Grab the next task */
+       task = rt_mutex_owner(lock);
+       spin_lock_irqsave(&task->pi_lock, flags);
+
+       if (waiter == rt_mutex_top_waiter(lock)) {
+               /* Boost the owner */
+               plist_del(&top_waiter->pi_list_entry, &task->pi_waiters);
+               waiter->pi_list_entry.prio = waiter->list_entry.prio;
+               plist_add(&waiter->pi_list_entry, &task->pi_waiters);
+               __rt_mutex_adjust_prio(task);
+
+       } else if (top_waiter == waiter) {
+               /* Deboost the owner */
+               plist_del(&waiter->pi_list_entry, &task->pi_waiters);
+               waiter = rt_mutex_top_waiter(lock);
+               waiter->pi_list_entry.prio = waiter->list_entry.prio;
+               plist_add(&waiter->pi_list_entry, &task->pi_waiters);
+               __rt_mutex_adjust_prio(task);
+       }
+
+       get_task_struct(task);
+       spin_unlock_irqrestore(&task->pi_lock, flags);
+
+       top_waiter = rt_mutex_top_waiter(lock);
+       spin_unlock(&lock->wait_lock);
+
+       if (!detect_deadlock && waiter != top_waiter)
+               goto out_put_task;
+
+       goto again;
+
+ out_unlock_pi:
+       spin_unlock_irqrestore(&task->pi_lock, flags);
+ out_put_task:
+       put_task_struct(task);
+       return ret;
+}
+
+/*
+ * Optimization: check if we can steal the lock from the
+ * assigned pending owner [which might not have taken the
+ * lock yet]:
+ */
+static inline int try_to_steal_lock(struct rt_mutex *lock)
+{
+       struct task_struct *pendowner = rt_mutex_owner(lock);
+       struct rt_mutex_waiter *next;
+       unsigned long flags;
+
+       if (!rt_mutex_owner_pending(lock))
+               return 0;
+
+       if (pendowner == current)
+               return 1;
+
+       spin_lock_irqsave(&pendowner->pi_lock, flags);
+       if (current->prio >= pendowner->prio) {
+               spin_unlock_irqrestore(&pendowner->pi_lock, flags);
+               return 0;
+       }
+
+       /*
+        * Check if a waiter is enqueued on the pending owners
+        * pi_waiters list. Remove it and readjust pending owners
+        * priority.
+        */
+       if (likely(!rt_mutex_has_waiters(lock))) {
+               spin_unlock_irqrestore(&pendowner->pi_lock, flags);
+               return 1;
+       }
+
+       /* No chain handling, pending owner is not blocked on anything: */
+       next = rt_mutex_top_waiter(lock);
+       plist_del(&next->pi_list_entry, &pendowner->pi_waiters);
+       __rt_mutex_adjust_prio(pendowner);
+       spin_unlock_irqrestore(&pendowner->pi_lock, flags);
+
+       /*
+        * We are going to steal the lock and a waiter was
+        * enqueued on the pending owners pi_waiters queue. So
+        * we have to enqueue this waiter into
+        * current->pi_waiters list. This covers the case,
+        * where current is boosted because it holds another
+        * lock and gets unboosted because the booster is
+        * interrupted, so we would delay a waiter with higher
+        * priority as current->normal_prio.
+        *
+        * Note: in the rare case of a SCHED_OTHER task changing
+        * its priority and thus stealing the lock, next->task
+        * might be current:
+        */
+       if (likely(next->task != current)) {
+               spin_lock_irqsave(&current->pi_lock, flags);
+               plist_add(&next->pi_list_entry, &current->pi_waiters);
+               __rt_mutex_adjust_prio(current);
+               spin_unlock_irqrestore(&current->pi_lock, flags);
+       }
+       return 1;
+}
+
+/*
+ * Try to take an rt-mutex
+ *
+ * This fails
+ * - when the lock has a real owner
+ * - when a different pending owner exists and has higher priority than current
+ *
+ * Must be called with lock->wait_lock held.
+ */
+static int try_to_take_rt_mutex(struct rt_mutex *lock __IP_DECL__)
+{
+       /*
+        * We have to be careful here if the atomic speedups are
+        * enabled, such that, when
+        *  - no other waiter is on the lock
+        *  - the lock has been released since we did the cmpxchg
+        * the lock can be released or taken while we are doing the
+        * checks and marking the lock with RT_MUTEX_HAS_WAITERS.
+        *
+        * The atomic acquire/release aware variant of
+        * mark_rt_mutex_waiters uses a cmpxchg loop. After setting
+        * the WAITERS bit, the atomic release / acquire can not
+        * happen anymore and lock->wait_lock protects us from the
+        * non-atomic case.
+        *
+        * Note, that this might set lock->owner =
+        * RT_MUTEX_HAS_WAITERS in the case the lock is not contended
+        * any more. This is fixed up when we take the ownership.
+        * This is the transitional state explained at the top of this file.
+        */
+       mark_rt_mutex_waiters(lock);
+
+       if (rt_mutex_owner(lock) && !try_to_steal_lock(lock))
+               return 0;
+
+       /* We got the lock. */
+       debug_rt_mutex_lock(lock __IP__);
+
+       rt_mutex_set_owner(lock, current, 0);
+
+       rt_mutex_deadlock_account_lock(lock, current);
+
+       return 1;
+}
+
+/*
+ * Task blocks on lock.
+ *
+ * Prepare waiter and propagate pi chain
+ *
+ * This must be called with lock->wait_lock held.
+ */
+static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
+                                  struct rt_mutex_waiter *waiter,
+                                  int detect_deadlock
+                                  __IP_DECL__)
+{
+       struct rt_mutex_waiter *top_waiter = waiter;
+       task_t *owner = rt_mutex_owner(lock);
+       int boost = 0, res;
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->pi_lock, flags);
+       __rt_mutex_adjust_prio(current);
+       waiter->task = current;
+       waiter->lock = lock;
+       plist_node_init(&waiter->list_entry, current->prio);
+       plist_node_init(&waiter->pi_list_entry, current->prio);
+
+       /* Get the top priority waiter on the lock */
+       if (rt_mutex_has_waiters(lock))
+               top_waiter = rt_mutex_top_waiter(lock);
+       plist_add(&waiter->list_entry, &lock->wait_list);
+
+       current->pi_blocked_on = waiter;
+
+       spin_unlock_irqrestore(&current->pi_lock, flags);
+
+       if (waiter == rt_mutex_top_waiter(lock)) {
+               spin_lock_irqsave(&owner->pi_lock, flags);
+               plist_del(&top_waiter->pi_list_entry, &owner->pi_waiters);
+               plist_add(&waiter->pi_list_entry, &owner->pi_waiters);
+
+               __rt_mutex_adjust_prio(owner);
+               if (owner->pi_blocked_on) {
+                       boost = 1;
+                       /* gets dropped in rt_mutex_adjust_prio_chain()! */
+                       get_task_struct(owner);
+               }
+               spin_unlock_irqrestore(&owner->pi_lock, flags);
+       }
+       else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) {
+               spin_lock_irqsave(&owner->pi_lock, flags);
+               if (owner->pi_blocked_on) {
+                       boost = 1;
+                       /* gets dropped in rt_mutex_adjust_prio_chain()! */
+                       get_task_struct(owner);
+               }
+               spin_unlock_irqrestore(&owner->pi_lock, flags);
+       }
+       if (!boost)
+               return 0;
+
+       spin_unlock(&lock->wait_lock);
+
+       res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter,
+                                        current __IP__);
+
+       spin_lock(&lock->wait_lock);
+
+       return res;
+}
+
+/*
+ * Wake up the next waiter on the lock.
+ *
+ * Remove the top waiter from the current tasks waiter list and from
+ * the lock waiter list. Set it as pending owner. Then wake it up.
+ *
+ * Called with lock->wait_lock held.
+ */
+static void wakeup_next_waiter(struct rt_mutex *lock)
+{
+       struct rt_mutex_waiter *waiter;
+       struct task_struct *pendowner;
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->pi_lock, flags);
+
+       waiter = rt_mutex_top_waiter(lock);
+       plist_del(&waiter->list_entry, &lock->wait_list);
+
+       /*
+        * Remove it from current->pi_waiters. We do not adjust a
+        * possible priority boost right now. We execute wakeup in the
+        * boosted mode and go back to normal after releasing
+        * lock->wait_lock.
+        */
+       plist_del(&waiter->pi_list_entry, &current->pi_waiters);
+       pendowner = waiter->task;
+       waiter->task = NULL;
+
+       rt_mutex_set_owner(lock, pendowner, RT_MUTEX_OWNER_PENDING);
+
+       spin_unlock_irqrestore(&current->pi_lock, flags);
+
+       /*
+        * Clear the pi_blocked_on variable and enqueue a possible
+        * waiter into the pi_waiters list of the pending owner. This
+        * prevents that in case the pending owner gets unboosted a
+        * waiter with higher priority than pending-owner->normal_prio
+        * is blocked on the unboosted (pending) owner.
+        */
+       spin_lock_irqsave(&pendowner->pi_lock, flags);
+
+       WARN_ON(!pendowner->pi_blocked_on);
+       WARN_ON(pendowner->pi_blocked_on != waiter);
+       WARN_ON(pendowner->pi_blocked_on->lock != lock);
+
+       pendowner->pi_blocked_on = NULL;
+
+       if (rt_mutex_has_waiters(lock)) {
+               struct rt_mutex_waiter *next;
+
+               next = rt_mutex_top_waiter(lock);
+               plist_add(&next->pi_list_entry, &pendowner->pi_waiters);
+       }
+       spin_unlock_irqrestore(&pendowner->pi_lock, flags);
+
+       wake_up_process(pendowner);
+}
+
+/*
+ * Remove a waiter from a lock
+ *
+ * Must be called with lock->wait_lock held
+ */
+static void remove_waiter(struct rt_mutex *lock,
+                         struct rt_mutex_waiter *waiter  __IP_DECL__)
+{
+       int first = (waiter == rt_mutex_top_waiter(lock));
+       int boost = 0;
+       task_t *owner = rt_mutex_owner(lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->pi_lock, flags);
+       plist_del(&waiter->list_entry, &lock->wait_list);
+       waiter->task = NULL;
+       current->pi_blocked_on = NULL;
+       spin_unlock_irqrestore(&current->pi_lock, flags);
+
+       if (first && owner != current) {
+
+               spin_lock_irqsave(&owner->pi_lock, flags);
+
+               plist_del(&waiter->pi_list_entry, &owner->pi_waiters);
+
+               if (rt_mutex_has_waiters(lock)) {
+                       struct rt_mutex_waiter *next;
+
+                       next = rt_mutex_top_waiter(lock);
+                       plist_add(&next->pi_list_entry, &owner->pi_waiters);
+               }
+               __rt_mutex_adjust_prio(owner);
+
+               if (owner->pi_blocked_on) {
+                       boost = 1;
+                       /* gets dropped in rt_mutex_adjust_prio_chain()! */
+                       get_task_struct(owner);
+               }
+               spin_unlock_irqrestore(&owner->pi_lock, flags);
+       }
+
+       WARN_ON(!plist_node_empty(&waiter->pi_list_entry));
+
+       if (!boost)
+               return;
+
+       spin_unlock(&lock->wait_lock);
+
+       rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current __IP__);
+
+       spin_lock(&lock->wait_lock);
+}
+
+/*
+ * Recheck the pi chain, in case we got a priority setting
+ *
+ * Called from sched_setscheduler
+ */
+void rt_mutex_adjust_pi(struct task_struct *task)
+{
+       struct rt_mutex_waiter *waiter;
+       unsigned long flags;
+
+       spin_lock_irqsave(&task->pi_lock, flags);
+
+       waiter = task->pi_blocked_on;
+       if (!waiter || waiter->list_entry.prio == task->prio) {
+               spin_unlock_irqrestore(&task->pi_lock, flags);
+               return;
+       }
+
+       /* gets dropped in rt_mutex_adjust_prio_chain()! */
+       get_task_struct(task);
+       spin_unlock_irqrestore(&task->pi_lock, flags);
+
+       rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task __RET_IP__);
+}
+
+/*
+ * Slow path lock function:
+ */
+static int __sched
+rt_mutex_slowlock(struct rt_mutex *lock, int state,
+                 struct hrtimer_sleeper *timeout,
+                 int detect_deadlock __IP_DECL__)
+{
+       struct rt_mutex_waiter waiter;
+       int ret = 0;
+
+       debug_rt_mutex_init_waiter(&waiter);
+       waiter.task = NULL;
+
+       spin_lock(&lock->wait_lock);
+
+       /* Try to acquire the lock again: */
+       if (try_to_take_rt_mutex(lock __IP__)) {
+               spin_unlock(&lock->wait_lock);
+               return 0;
+       }
+
+       set_current_state(state);
+
+       /* Setup the timer, when timeout != NULL */
+       if (unlikely(timeout))
+               hrtimer_start(&timeout->timer, timeout->timer.expires,
+                             HRTIMER_ABS);
+
+       for (;;) {
+               /* Try to acquire the lock: */
+               if (try_to_take_rt_mutex(lock __IP__))
+                       break;
+
+               /*
+                * TASK_INTERRUPTIBLE checks for signals and
+                * timeout. Ignored otherwise.
+                */
+               if (unlikely(state == TASK_INTERRUPTIBLE)) {
+                       /* Signal pending? */
+                       if (signal_pending(current))
+                               ret = -EINTR;
+                       if (timeout && !timeout->task)
+                               ret = -ETIMEDOUT;
+                       if (ret)
+                               break;
+               }
+
+               /*
+                * waiter.task is NULL the first time we come here and
+                * when we have been woken up by the previous owner
+                * but the lock got stolen by a higher prio task.
+                */
+               if (!waiter.task) {
+                       ret = task_blocks_on_rt_mutex(lock, &waiter,
+                                                     detect_deadlock __IP__);
+                       /*
+                        * If we got woken up by the owner then start loop
+                        * all over without going into schedule to try
+                        * to get the lock now:
+                        */
+                       if (unlikely(!waiter.task))
+                               continue;
+
+                       if (unlikely(ret))
+                               break;
+               }
+
+               spin_unlock(&lock->wait_lock);
+
+               debug_rt_mutex_print_deadlock(&waiter);
+
+               if (waiter.task)
+                       schedule_rt_mutex(lock);
+
+               spin_lock(&lock->wait_lock);
+               set_current_state(state);
+       }
+
+       set_current_state(TASK_RUNNING);
+
+       if (unlikely(waiter.task))
+               remove_waiter(lock, &waiter __IP__);
+
+       /*
+        * try_to_take_rt_mutex() sets the waiter bit
+        * unconditionally. We might have to fix that up.
+        */
+       fixup_rt_mutex_waiters(lock);
+
+       spin_unlock(&lock->wait_lock);
+
+       /* Remove pending timer: */
+       if (unlikely(timeout))
+               hrtimer_cancel(&timeout->timer);
+
+       /*
+        * Readjust priority, when we did not get the lock. We might
+        * have been the pending owner and boosted. Since we did not
+        * take the lock, the PI boost has to go.
+        */
+       if (unlikely(ret))
+               rt_mutex_adjust_prio(current);
+
+       debug_rt_mutex_free_waiter(&waiter);
+
+       return ret;
+}
+
+/*
+ * Slow path try-lock function:
+ */
+static inline int
+rt_mutex_slowtrylock(struct rt_mutex *lock __IP_DECL__)
+{
+       int ret = 0;
+
+       spin_lock(&lock->wait_lock);
+
+       if (likely(rt_mutex_owner(lock) != current)) {
+
+               ret = try_to_take_rt_mutex(lock __IP__);
+               /*
+                * try_to_take_rt_mutex() sets the lock waiters
+                * bit unconditionally. Clean this up.
+                */
+               fixup_rt_mutex_waiters(lock);
+       }
+
+       spin_unlock(&lock->wait_lock);
+
+       return ret;
+}
+
+/*
+ * Slow path to release a rt-mutex:
+ */
+static void __sched
+rt_mutex_slowunlock(struct rt_mutex *lock)
+{
+       spin_lock(&lock->wait_lock);
+
+       debug_rt_mutex_unlock(lock);
+
+       rt_mutex_deadlock_account_unlock(current);
+
+       if (!rt_mutex_has_waiters(lock)) {
+               lock->owner = NULL;
+               spin_unlock(&lock->wait_lock);
+               return;
+       }
+
+       wakeup_next_waiter(lock);
+
+       spin_unlock(&lock->wait_lock);
+
+       /* Undo pi boosting if necessary: */
+       rt_mutex_adjust_prio(current);
+}
+
+/*
+ * debug aware fast / slowpath lock,trylock,unlock
+ *
+ * The atomic acquire/release ops are compiled away, when either the
+ * architecture does not support cmpxchg or when debugging is enabled.
+ */
+static inline int
+rt_mutex_fastlock(struct rt_mutex *lock, int state,
+                 int detect_deadlock,
+                 int (*slowfn)(struct rt_mutex *lock, int state,
+                               struct hrtimer_sleeper *timeout,
+                               int detect_deadlock __IP_DECL__))
+{
+       if (!detect_deadlock && likely(rt_mutex_cmpxchg(lock, NULL, current))) {
+               rt_mutex_deadlock_account_lock(lock, current);
+               return 0;
+       } else
+               return slowfn(lock, state, NULL, detect_deadlock __RET_IP__);
+}
+
+static inline int
+rt_mutex_timed_fastlock(struct rt_mutex *lock, int state,
+                       struct hrtimer_sleeper *timeout, int detect_deadlock,
+                       int (*slowfn)(struct rt_mutex *lock, int state,
+                                     struct hrtimer_sleeper *timeout,
+                                     int detect_deadlock __IP_DECL__))
+{
+       if (!detect_deadlock && likely(rt_mutex_cmpxchg(lock, NULL, current))) {
+               rt_mutex_deadlock_account_lock(lock, current);
+               return 0;
+       } else
+               return slowfn(lock, state, timeout, detect_deadlock __RET_IP__);
+}
+
+static inline int
+rt_mutex_fasttrylock(struct rt_mutex *lock,
+                    int (*slowfn)(struct rt_mutex *lock __IP_DECL__))
+{
+       if (likely(rt_mutex_cmpxchg(lock, NULL, current))) {
+               rt_mutex_deadlock_account_lock(lock, current);
+               return 1;
+       }
+       return slowfn(lock __RET_IP__);
+}
+
+static inline void
+rt_mutex_fastunlock(struct rt_mutex *lock,
+                   void (*slowfn)(struct rt_mutex *lock))
+{
+       if (likely(rt_mutex_cmpxchg(lock, current, NULL)))
+               rt_mutex_deadlock_account_unlock(current);
+       else
+               slowfn(lock);
+}
+
+/**
+ * rt_mutex_lock - lock a rt_mutex
+ *
+ * @lock: the rt_mutex to be locked
+ */
+void __sched rt_mutex_lock(struct rt_mutex *lock)
+{
+       might_sleep();
+
+       rt_mutex_fastlock(lock, TASK_UNINTERRUPTIBLE, 0, rt_mutex_slowlock);
+}
+EXPORT_SYMBOL_GPL(rt_mutex_lock);
+
+/**
+ * rt_mutex_lock_interruptible - lock a rt_mutex interruptible
+ *
+ * @lock:              the rt_mutex to be locked
+ * @detect_deadlock:   deadlock detection on/off
+ *
+ * Returns:
+ *  0          on success
+ * -EINTR      when interrupted by a signal
+ * -EDEADLK    when the lock would deadlock (when deadlock detection is on)
+ */
+int __sched rt_mutex_lock_interruptible(struct rt_mutex *lock,
+                                                int detect_deadlock)
+{
+       might_sleep();
+
+       return rt_mutex_fastlock(lock, TASK_INTERRUPTIBLE,
+                                detect_deadlock, rt_mutex_slowlock);
+}
+EXPORT_SYMBOL_GPL(rt_mutex_lock_interruptible);
+
+/**
+ * rt_mutex_lock_interruptible_ktime - lock a rt_mutex interruptible
+ *                                    the timeout structure is provided
+ *                                    by the caller
+ *
+ * @lock:              the rt_mutex to be locked
+ * @timeout:           timeout structure or NULL (no timeout)
+ * @detect_deadlock:   deadlock detection on/off
+ *
+ * Returns:
+ *  0          on success
+ * -EINTR      when interrupted by a signal
+ * -ETIMEOUT   when the timeout expired
+ * -EDEADLK    when the lock would deadlock (when deadlock detection is on)
+ */
+int
+rt_mutex_timed_lock(struct rt_mutex *lock, struct hrtimer_sleeper *timeout,
+                   int detect_deadlock)
+{
+       might_sleep();
+
+       return rt_mutex_timed_fastlock(lock, TASK_INTERRUPTIBLE, timeout,
+                                      detect_deadlock, rt_mutex_slowlock);
+}
+EXPORT_SYMBOL_GPL(rt_mutex_timed_lock);
+
+/**
+ * rt_mutex_trylock - try to lock a rt_mutex
+ *
+ * @lock:      the rt_mutex to be locked
+ *
+ * Returns 1 on success and 0 on contention
+ */
+int __sched rt_mutex_trylock(struct rt_mutex *lock)
+{
+       return rt_mutex_fasttrylock(lock, rt_mutex_slowtrylock);
+}
+EXPORT_SYMBOL_GPL(rt_mutex_trylock);
+
+/**
+ * rt_mutex_unlock - unlock a rt_mutex
+ *
+ * @lock: the rt_mutex to be unlocked
+ */
+void __sched rt_mutex_unlock(struct rt_mutex *lock)
+{
+       rt_mutex_fastunlock(lock, rt_mutex_slowunlock);
+}
+EXPORT_SYMBOL_GPL(rt_mutex_unlock);
+
+/***
+ * rt_mutex_destroy - mark a mutex unusable
+ * @lock: the mutex to be destroyed
+ *
+ * This function marks the mutex uninitialized, and any subsequent
+ * use of the mutex is forbidden. The mutex must not be locked when
+ * this function is called.
+ */
+void rt_mutex_destroy(struct rt_mutex *lock)
+{
+       WARN_ON(rt_mutex_is_locked(lock));
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+       lock->magic = NULL;
+#endif
+}
+
+EXPORT_SYMBOL_GPL(rt_mutex_destroy);
+
+/**
+ * __rt_mutex_init - initialize the rt lock
+ *
+ * @lock: the rt lock to be initialized
+ *
+ * Initialize the rt lock to unlocked state.
+ *
+ * Initializing of a locked rt lock is not allowed
+ */
+void __rt_mutex_init(struct rt_mutex *lock, const char *name)
+{
+       lock->owner = NULL;
+       spin_lock_init(&lock->wait_lock);
+       plist_head_init(&lock->wait_list, &lock->wait_lock);
+
+       debug_rt_mutex_init(lock, name);
+}
+EXPORT_SYMBOL_GPL(__rt_mutex_init);
+
+/**
+ * rt_mutex_init_proxy_locked - initialize and lock a rt_mutex on behalf of a
+ *                             proxy owner
+ *
+ * @lock:      the rt_mutex to be locked
+ * @proxy_owner:the task to set as owner
+ *
+ * No locking. Caller has to do serializing itself
+ * Special API call for PI-futex support
+ */
+void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
+                               struct task_struct *proxy_owner)
+{
+       __rt_mutex_init(lock, NULL);
+       debug_rt_mutex_proxy_lock(lock, proxy_owner __RET_IP__);
+       rt_mutex_set_owner(lock, proxy_owner, 0);
+       rt_mutex_deadlock_account_lock(lock, proxy_owner);
+}
+
+/**
+ * rt_mutex_proxy_unlock - release a lock on behalf of owner
+ *
+ * @lock:      the rt_mutex to be locked
+ *
+ * No locking. Caller has to do serializing itself
+ * Special API call for PI-futex support
+ */
+void rt_mutex_proxy_unlock(struct rt_mutex *lock,
+                          struct task_struct *proxy_owner)
+{
+       debug_rt_mutex_proxy_unlock(lock);
+       rt_mutex_set_owner(lock, NULL, 0);
+       rt_mutex_deadlock_account_unlock(proxy_owner);
+}
+
+/**
+ * rt_mutex_next_owner - return the next owner of the lock
+ *
+ * @lock: the rt lock query
+ *
+ * Returns the next owner of the lock or NULL
+ *
+ * Caller has to serialize against other accessors to the lock
+ * itself.
+ *
+ * Special API call for PI-futex support
+ */
+struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock)
+{
+       if (!rt_mutex_has_waiters(lock))
+               return NULL;
+
+       return rt_mutex_top_waiter(lock)->task;
+}
diff --git a/kernel/rtmutex.h b/kernel/rtmutex.h
new file mode 100644 (file)
index 0000000..1e0fca1
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * RT-Mutexes: blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner:
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ * This file contains macros used solely by rtmutex.c.
+ * Non-debug version.
+ */
+
+#define __IP_DECL__
+#define __IP__
+#define __RET_IP__
+#define rt_mutex_deadlock_check(l)                     (0)
+#define rt_mutex_deadlock_account_lock(m, t)           do { } while (0)
+#define rt_mutex_deadlock_account_unlock(l)            do { } while (0)
+#define debug_rt_mutex_init_waiter(w)                  do { } while (0)
+#define debug_rt_mutex_free_waiter(w)                  do { } while (0)
+#define debug_rt_mutex_lock(l)                         do { } while (0)
+#define debug_rt_mutex_proxy_lock(l,p)                 do { } while (0)
+#define debug_rt_mutex_proxy_unlock(l)                 do { } while (0)
+#define debug_rt_mutex_unlock(l)                       do { } while (0)
+#define debug_rt_mutex_init(m, n)                      do { } while (0)
+#define debug_rt_mutex_deadlock(d, a ,l)               do { } while (0)
+#define debug_rt_mutex_print_deadlock(w)               do { } while (0)
+#define debug_rt_mutex_detect_deadlock(w,d)            (d)
+#define debug_rt_mutex_reset_waiter(w)                 do { } while (0)
diff --git a/kernel/rtmutex_common.h b/kernel/rtmutex_common.h
new file mode 100644 (file)
index 0000000..9c75856
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * RT Mutexes: blocking mutual exclusion locks with PI support
+ *
+ * started by Ingo Molnar and Thomas Gleixner:
+ *
+ *  Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
+ *
+ * This file contains the private data structure and API definitions.
+ */
+
+#ifndef __KERNEL_RTMUTEX_COMMON_H
+#define __KERNEL_RTMUTEX_COMMON_H
+
+#include <linux/rtmutex.h>
+
+/*
+ * The rtmutex in kernel tester is independent of rtmutex debugging. We
+ * call schedule_rt_mutex_test() instead of schedule() for the tasks which
+ * belong to the tester. That way we can delay the wakeup path of those
+ * threads to provoke lock stealing and testing of  complex boosting scenarios.
+ */
+#ifdef CONFIG_RT_MUTEX_TESTER
+
+extern void schedule_rt_mutex_test(struct rt_mutex *lock);
+
+#define schedule_rt_mutex(_lock)                               \
+  do {                                                         \
+       if (!(current->flags & PF_MUTEX_TESTER))                \
+               schedule();                                     \
+       else                                                    \
+               schedule_rt_mutex_test(_lock);                  \
+  } while (0)
+
+#else
+# define schedule_rt_mutex(_lock)                      schedule()
+#endif
+
+/*
+ * This is the control structure for tasks blocked on a rt_mutex,
+ * which is allocated on the kernel stack on of the blocked task.
+ *
+ * @list_entry:                pi node to enqueue into the mutex waiters list
+ * @pi_list_entry:     pi node to enqueue into the mutex owner waiters list
+ * @task:              task reference to the blocked task
+ */
+struct rt_mutex_waiter {
+       struct plist_node       list_entry;
+       struct plist_node       pi_list_entry;
+       struct task_struct      *task;
+       struct rt_mutex         *lock;
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+       unsigned long           ip;
+       pid_t                   deadlock_task_pid;
+       struct rt_mutex         *deadlock_lock;
+#endif
+};
+
+/*
+ * Various helpers to access the waiters-plist:
+ */
+static inline int rt_mutex_has_waiters(struct rt_mutex *lock)
+{
+       return !plist_head_empty(&lock->wait_list);
+}
+
+static inline struct rt_mutex_waiter *
+rt_mutex_top_waiter(struct rt_mutex *lock)
+{
+       struct rt_mutex_waiter *w;
+
+       w = plist_first_entry(&lock->wait_list, struct rt_mutex_waiter,
+                              list_entry);
+       BUG_ON(w->lock != lock);
+
+       return w;
+}
+
+static inline int task_has_pi_waiters(struct task_struct *p)
+{
+       return !plist_head_empty(&p->pi_waiters);
+}
+
+static inline struct rt_mutex_waiter *
+task_top_pi_waiter(struct task_struct *p)
+{
+       return plist_first_entry(&p->pi_waiters, struct rt_mutex_waiter,
+                                 pi_list_entry);
+}
+
+/*
+ * lock->owner state tracking:
+ */
+#define RT_MUTEX_OWNER_PENDING 1UL
+#define RT_MUTEX_HAS_WAITERS   2UL
+#define RT_MUTEX_OWNER_MASKALL 3UL
+
+static inline struct task_struct *rt_mutex_owner(struct rt_mutex *lock)
+{
+       return (struct task_struct *)
+               ((unsigned long)lock->owner & ~RT_MUTEX_OWNER_MASKALL);
+}
+
+static inline struct task_struct *rt_mutex_real_owner(struct rt_mutex *lock)
+{
+       return (struct task_struct *)
+               ((unsigned long)lock->owner & ~RT_MUTEX_HAS_WAITERS);
+}
+
+static inline unsigned long rt_mutex_owner_pending(struct rt_mutex *lock)
+{
+       return (unsigned long)lock->owner & RT_MUTEX_OWNER_PENDING;
+}
+
+/*
+ * PI-futex support (proxy locking functions, etc.):
+ */
+extern struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock);
+extern void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
+                                      struct task_struct *proxy_owner);
+extern void rt_mutex_proxy_unlock(struct rt_mutex *lock,
+                                 struct task_struct *proxy_owner);
+#endif
index a856040c200a4213bd8b0b2d8b469e25bcc1d57f..2629c1711fd62be84574153e0ae62077895f3b36 100644 (file)
  */
 
 #define SCALE_PRIO(x, prio) \
-       max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE)
+       max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
 
-static unsigned int task_timeslice(task_t *p)
+static unsigned int static_prio_timeslice(int static_prio)
 {
-       if (p->static_prio < NICE_TO_PRIO(0))
-               return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);
+       if (static_prio < NICE_TO_PRIO(0))
+               return SCALE_PRIO(DEF_TIMESLICE * 4, static_prio);
        else
-               return SCALE_PRIO(DEF_TIMESLICE, p->static_prio);
+               return SCALE_PRIO(DEF_TIMESLICE, static_prio);
 }
+
+static inline unsigned int task_timeslice(task_t *p)
+{
+       return static_prio_timeslice(p->static_prio);
+}
+
 #define task_hot(p, now, sd) ((long long) ((now) - (p)->last_ran)      \
                                < (long long) (sd)->cache_hot_time)
 
@@ -184,13 +190,11 @@ static unsigned int task_timeslice(task_t *p)
  * These are the runqueue data structures:
  */
 
-#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long))
-
 typedef struct runqueue runqueue_t;
 
 struct prio_array {
        unsigned int nr_active;
-       unsigned long bitmap[BITMAP_SIZE];
+       DECLARE_BITMAP(bitmap, MAX_PRIO+1); /* include 1 bit for delimiter */
        struct list_head queue[MAX_PRIO];
 };
 
@@ -209,6 +213,7 @@ struct runqueue {
         * remote CPUs use both these fields when doing load calculation.
         */
        unsigned long nr_running;
+       unsigned long raw_weighted_load;
 #ifdef CONFIG_SMP
        unsigned long cpu_load[3];
 #endif
@@ -239,7 +244,6 @@ struct runqueue {
 
        task_t *migration_thread;
        struct list_head migration_queue;
-       int cpu;
 #endif
 
 #ifdef CONFIG_SCHEDSTATS
@@ -350,12 +354,31 @@ static inline void finish_lock_switch(runqueue_t *rq, task_t *prev)
 }
 #endif /* __ARCH_WANT_UNLOCKED_CTXSW */
 
+/*
+ * __task_rq_lock - lock the runqueue a given task resides on.
+ * Must be called interrupts disabled.
+ */
+static inline runqueue_t *__task_rq_lock(task_t *p)
+       __acquires(rq->lock)
+{
+       struct runqueue *rq;
+
+repeat_lock_task:
+       rq = task_rq(p);
+       spin_lock(&rq->lock);
+       if (unlikely(rq != task_rq(p))) {
+               spin_unlock(&rq->lock);
+               goto repeat_lock_task;
+       }
+       return rq;
+}
+
 /*
  * task_rq_lock - lock the runqueue a given task resides on and disable
  * interrupts.  Note the ordering: we can safely lookup the task_rq without
  * explicitly disabling preemption.
  */
-static inline runqueue_t *task_rq_lock(task_t *p, unsigned long *flags)
+static runqueue_t *task_rq_lock(task_t *p, unsigned long *flags)
        __acquires(rq->lock)
 {
        struct runqueue *rq;
@@ -371,6 +394,12 @@ repeat_lock_task:
        return rq;
 }
 
+static inline void __task_rq_unlock(runqueue_t *rq)
+       __releases(rq->lock)
+{
+       spin_unlock(&rq->lock);
+}
+
 static inline void task_rq_unlock(runqueue_t *rq, unsigned long *flags)
        __releases(rq->lock)
 {
@@ -634,7 +663,7 @@ static inline void enqueue_task_head(struct task_struct *p, prio_array_t *array)
 }
 
 /*
- * effective_prio - return the priority that is based on the static
+ * __normal_prio - return the priority that is based on the static
  * priority but is modified by bonuses/penalties.
  *
  * We scale the actual sleep average [0 .... MAX_SLEEP_AVG]
@@ -647,13 +676,11 @@ static inline void enqueue_task_head(struct task_struct *p, prio_array_t *array)
  *
  * Both properties are important to certain workloads.
  */
-static int effective_prio(task_t *p)
+
+static inline int __normal_prio(task_t *p)
 {
        int bonus, prio;
 
-       if (rt_task(p))
-               return p->prio;
-
        bonus = CURRENT_BONUS(p) - MAX_BONUS / 2;
 
        prio = p->static_prio - bonus;
@@ -664,6 +691,106 @@ static int effective_prio(task_t *p)
        return prio;
 }
 
+/*
+ * To aid in avoiding the subversion of "niceness" due to uneven distribution
+ * of tasks with abnormal "nice" values across CPUs the contribution that
+ * each task makes to its run queue's load is weighted according to its
+ * scheduling class and "nice" value.  For SCHED_NORMAL tasks this is just a
+ * scaled version of the new time slice allocation that they receive on time
+ * slice expiry etc.
+ */
+
+/*
+ * Assume: static_prio_timeslice(NICE_TO_PRIO(0)) == DEF_TIMESLICE
+ * If static_prio_timeslice() is ever changed to break this assumption then
+ * this code will need modification
+ */
+#define TIME_SLICE_NICE_ZERO DEF_TIMESLICE
+#define LOAD_WEIGHT(lp) \
+       (((lp) * SCHED_LOAD_SCALE) / TIME_SLICE_NICE_ZERO)
+#define PRIO_TO_LOAD_WEIGHT(prio) \
+       LOAD_WEIGHT(static_prio_timeslice(prio))
+#define RTPRIO_TO_LOAD_WEIGHT(rp) \
+       (PRIO_TO_LOAD_WEIGHT(MAX_RT_PRIO) + LOAD_WEIGHT(rp))
+
+static void set_load_weight(task_t *p)
+{
+       if (has_rt_policy(p)) {
+#ifdef CONFIG_SMP
+               if (p == task_rq(p)->migration_thread)
+                       /*
+                        * The migration thread does the actual balancing.
+                        * Giving its load any weight will skew balancing
+                        * adversely.
+                        */
+                       p->load_weight = 0;
+               else
+#endif
+                       p->load_weight = RTPRIO_TO_LOAD_WEIGHT(p->rt_priority);
+       } else
+               p->load_weight = PRIO_TO_LOAD_WEIGHT(p->static_prio);
+}
+
+static inline void inc_raw_weighted_load(runqueue_t *rq, const task_t *p)
+{
+       rq->raw_weighted_load += p->load_weight;
+}
+
+static inline void dec_raw_weighted_load(runqueue_t *rq, const task_t *p)
+{
+       rq->raw_weighted_load -= p->load_weight;
+}
+
+static inline void inc_nr_running(task_t *p, runqueue_t *rq)
+{
+       rq->nr_running++;
+       inc_raw_weighted_load(rq, p);
+}
+
+static inline void dec_nr_running(task_t *p, runqueue_t *rq)
+{
+       rq->nr_running--;
+       dec_raw_weighted_load(rq, p);
+}
+
+/*
+ * Calculate the expected normal priority: i.e. priority
+ * without taking RT-inheritance into account. Might be
+ * boosted by interactivity modifiers. Changes upon fork,
+ * setprio syscalls, and whenever the interactivity
+ * estimator recalculates.
+ */
+static inline int normal_prio(task_t *p)
+{
+       int prio;
+
+       if (has_rt_policy(p))
+               prio = MAX_RT_PRIO-1 - p->rt_priority;
+       else
+               prio = __normal_prio(p);
+       return prio;
+}
+
+/*
+ * Calculate the current priority, i.e. the priority
+ * taken into account by the scheduler. This value might
+ * be boosted by RT tasks, or might be boosted by
+ * interactivity modifiers. Will be RT if the task got
+ * RT-boosted. If not then it returns p->normal_prio.
+ */
+static int effective_prio(task_t *p)
+{
+       p->normal_prio = normal_prio(p);
+       /*
+        * If we are RT tasks or we were boosted to RT priority,
+        * keep the priority unchanged. Otherwise, update priority
+        * to the normal priority:
+        */
+       if (!rt_prio(p->prio))
+               return p->normal_prio;
+       return p->prio;
+}
+
 /*
  * __activate_task - move a task to the runqueue.
  */
@@ -674,7 +801,7 @@ static void __activate_task(task_t *p, runqueue_t *rq)
        if (batch_task(p))
                target = rq->expired;
        enqueue_task(p, target);
-       rq->nr_running++;
+       inc_nr_running(p, rq);
 }
 
 /*
@@ -683,39 +810,45 @@ static void __activate_task(task_t *p, runqueue_t *rq)
 static inline void __activate_idle_task(task_t *p, runqueue_t *rq)
 {
        enqueue_task_head(p, rq->active);
-       rq->nr_running++;
+       inc_nr_running(p, rq);
 }
 
+/*
+ * Recalculate p->normal_prio and p->prio after having slept,
+ * updating the sleep-average too:
+ */
 static int recalc_task_prio(task_t *p, unsigned long long now)
 {
        /* Caller must always ensure 'now >= p->timestamp' */
-       unsigned long long __sleep_time = now - p->timestamp;
-       unsigned long sleep_time;
+       unsigned long sleep_time = now - p->timestamp;
 
        if (batch_task(p))
                sleep_time = 0;
-       else {
-               if (__sleep_time > NS_MAX_SLEEP_AVG)
-                       sleep_time = NS_MAX_SLEEP_AVG;
-               else
-                       sleep_time = (unsigned long)__sleep_time;
-       }
 
        if (likely(sleep_time > 0)) {
                /*
-                * User tasks that sleep a long time are categorised as
-                * idle. They will only have their sleep_avg increased to a
-                * level that makes them just interactive priority to stay
-                * active yet prevent them suddenly becoming cpu hogs and
-                * starving other processes.
+                * This ceiling is set to the lowest priority that would allow
+                * a task to be reinserted into the active array on timeslice
+                * completion.
                 */
-               if (p->mm && sleep_time > INTERACTIVE_SLEEP(p)) {
-                               unsigned long ceiling;
+               unsigned long ceiling = INTERACTIVE_SLEEP(p);
 
-                               ceiling = JIFFIES_TO_NS(MAX_SLEEP_AVG -
-                                       DEF_TIMESLICE);
-                               if (p->sleep_avg < ceiling)
-                                       p->sleep_avg = ceiling;
+               if (p->mm && sleep_time > ceiling && p->sleep_avg < ceiling) {
+                       /*
+                        * Prevents user tasks from achieving best priority
+                        * with one single large enough sleep.
+                        */
+                       p->sleep_avg = ceiling;
+                       /*
+                        * Using INTERACTIVE_SLEEP() as a ceiling places a
+                        * nice(0) task 1ms sleep away from promotion, and
+                        * gives it 700ms to round-robin with no chance of
+                        * being demoted.  This is more than generous, so
+                        * mark this sleep as non-interactive to prevent the
+                        * on-runqueue bonus logic from intervening should
+                        * this task not receive cpu immediately.
+                        */
+                       p->sleep_type = SLEEP_NONINTERACTIVE;
                } else {
                        /*
                         * Tasks waking from uninterruptible sleep are
@@ -723,12 +856,12 @@ static int recalc_task_prio(task_t *p, unsigned long long now)
                         * are likely to be waiting on I/O
                         */
                        if (p->sleep_type == SLEEP_NONINTERACTIVE && p->mm) {
-                               if (p->sleep_avg >= INTERACTIVE_SLEEP(p))
+                               if (p->sleep_avg >= ceiling)
                                        sleep_time = 0;
                                else if (p->sleep_avg + sleep_time >=
-                                               INTERACTIVE_SLEEP(p)) {
-                                       p->sleep_avg = INTERACTIVE_SLEEP(p);
-                                       sleep_time = 0;
+                                        ceiling) {
+                                               p->sleep_avg = ceiling;
+                                               sleep_time = 0;
                                }
                        }
 
@@ -742,9 +875,9 @@ static int recalc_task_prio(task_t *p, unsigned long long now)
                         */
                        p->sleep_avg += sleep_time;
 
-                       if (p->sleep_avg > NS_MAX_SLEEP_AVG)
-                               p->sleep_avg = NS_MAX_SLEEP_AVG;
                }
+               if (p->sleep_avg > NS_MAX_SLEEP_AVG)
+                       p->sleep_avg = NS_MAX_SLEEP_AVG;
        }
 
        return effective_prio(p);
@@ -805,7 +938,7 @@ static void activate_task(task_t *p, runqueue_t *rq, int local)
  */
 static void deactivate_task(struct task_struct *p, runqueue_t *rq)
 {
-       rq->nr_running--;
+       dec_nr_running(p, rq);
        dequeue_task(p, p->array);
        p->array = NULL;
 }
@@ -860,6 +993,12 @@ inline int task_curr(const task_t *p)
        return cpu_curr(task_cpu(p)) == p;
 }
 
+/* Used instead of source_load when we know the type == 0 */
+unsigned long weighted_cpuload(const int cpu)
+{
+       return cpu_rq(cpu)->raw_weighted_load;
+}
+
 #ifdef CONFIG_SMP
 typedef struct {
        struct list_head list;
@@ -949,7 +1088,8 @@ void kick_process(task_t *p)
 }
 
 /*
- * Return a low guess at the load of a migration-source cpu.
+ * Return a low guess at the load of a migration-source cpu weighted
+ * according to the scheduling class and "nice" value.
  *
  * We want to under-estimate the load of migration sources, to
  * balance conservatively.
@@ -957,24 +1097,36 @@ void kick_process(task_t *p)
 static inline unsigned long source_load(int cpu, int type)
 {
        runqueue_t *rq = cpu_rq(cpu);
-       unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
+
        if (type == 0)
-               return load_now;
+               return rq->raw_weighted_load;
 
-       return min(rq->cpu_load[type-1], load_now);
+       return min(rq->cpu_load[type-1], rq->raw_weighted_load);
 }
 
 /*
- * Return a high guess at the load of a migration-target cpu
+ * Return a high guess at the load of a migration-target cpu weighted
+ * according to the scheduling class and "nice" value.
  */
 static inline unsigned long target_load(int cpu, int type)
 {
        runqueue_t *rq = cpu_rq(cpu);
-       unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
+
        if (type == 0)
-               return load_now;
+               return rq->raw_weighted_load;
+
+       return max(rq->cpu_load[type-1], rq->raw_weighted_load);
+}
+
+/*
+ * Return the average load per task on the cpu's run queue
+ */
+static inline unsigned long cpu_avg_load_per_task(int cpu)
+{
+       runqueue_t *rq = cpu_rq(cpu);
+       unsigned long n = rq->nr_running;
 
-       return max(rq->cpu_load[type-1], load_now);
+       return n ?  rq->raw_weighted_load / n : SCHED_LOAD_SCALE;
 }
 
 /*
@@ -1047,7 +1199,7 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
        cpus_and(tmp, group->cpumask, p->cpus_allowed);
 
        for_each_cpu_mask(i, tmp) {
-               load = source_load(i, 0);
+               load = weighted_cpuload(i);
 
                if (load < min_load || (load == min_load && i == this_cpu)) {
                        min_load = load;
@@ -1074,9 +1226,15 @@ static int sched_balance_self(int cpu, int flag)
        struct task_struct *t = current;
        struct sched_domain *tmp, *sd = NULL;
 
-       for_each_domain(cpu, tmp)
+       for_each_domain(cpu, tmp) {
+               /*
+                * If power savings logic is enabled for a domain, stop there.
+                */
+               if (tmp->flags & SD_POWERSAVINGS_BALANCE)
+                       break;
                if (tmp->flags & flag)
                        sd = tmp;
+       }
 
        while (sd) {
                cpumask_t span;
@@ -1226,17 +1384,19 @@ static int try_to_wake_up(task_t *p, unsigned int state, int sync)
 
                if (this_sd->flags & SD_WAKE_AFFINE) {
                        unsigned long tl = this_load;
+                       unsigned long tl_per_task = cpu_avg_load_per_task(this_cpu);
+
                        /*
                         * If sync wakeup then subtract the (maximum possible)
                         * effect of the currently running task from the load
                         * of the current CPU:
                         */
                        if (sync)
-                               tl -= SCHED_LOAD_SCALE;
+                               tl -= current->load_weight;
 
                        if ((tl <= load &&
-                               tl + target_load(cpu, idx) <= SCHED_LOAD_SCALE) ||
-                               100*(tl + SCHED_LOAD_SCALE) <= imbalance*load) {
+                               tl + target_load(cpu, idx) <= tl_per_task) ||
+                               100*(tl + p->load_weight) <= imbalance*load) {
                                /*
                                 * This domain has SD_WAKE_AFFINE and
                                 * p is cache cold in this domain, and
@@ -1353,6 +1513,12 @@ void fastcall sched_fork(task_t *p, int clone_flags)
         * event cannot wake it up and insert it on the runqueue either.
         */
        p->state = TASK_RUNNING;
+
+       /*
+        * Make sure we do not leak PI boosting priority to the child:
+        */
+       p->prio = current->normal_prio;
+
        INIT_LIST_HEAD(&p->run_list);
        p->array = NULL;
 #ifdef CONFIG_SCHEDSTATS
@@ -1432,10 +1598,11 @@ void fastcall wake_up_new_task(task_t *p, unsigned long clone_flags)
                                __activate_task(p, rq);
                        else {
                                p->prio = current->prio;
+                               p->normal_prio = current->normal_prio;
                                list_add_tail(&p->run_list, &current->run_list);
                                p->array = current->array;
                                p->array->nr_active++;
-                               rq->nr_running++;
+                               inc_nr_running(p, rq);
                        }
                        set_need_resched();
                } else
@@ -1653,7 +1820,8 @@ unsigned long nr_uninterruptible(void)
 
 unsigned long long nr_context_switches(void)
 {
-       unsigned long long i, sum = 0;
+       int i;
+       unsigned long long sum = 0;
 
        for_each_possible_cpu(i)
                sum += cpu_rq(i)->nr_switches;
@@ -1691,9 +1859,6 @@ unsigned long nr_active(void)
 /*
  * double_rq_lock - safely lock two runqueues
  *
- * We must take them in cpu order to match code in
- * dependent_sleeper and wake_dependent_sleeper.
- *
  * Note this does not disable interrupts like task_rq_lock,
  * you need to do so manually before calling.
  */
@@ -1705,7 +1870,7 @@ static void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
                spin_lock(&rq1->lock);
                __acquire(rq2->lock);   /* Fake it out ;) */
        } else {
-               if (rq1->cpu < rq2->cpu) {
+               if (rq1 < rq2) {
                        spin_lock(&rq1->lock);
                        spin_lock(&rq2->lock);
                } else {
@@ -1741,7 +1906,7 @@ static void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest)
        __acquires(this_rq->lock)
 {
        if (unlikely(!spin_trylock(&busiest->lock))) {
-               if (busiest->cpu < this_rq->cpu) {
+               if (busiest < this_rq) {
                        spin_unlock(&this_rq->lock);
                        spin_lock(&busiest->lock);
                        spin_lock(&this_rq->lock);
@@ -1804,9 +1969,9 @@ void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p,
               runqueue_t *this_rq, prio_array_t *this_array, int this_cpu)
 {
        dequeue_task(p, src_array);
-       src_rq->nr_running--;
+       dec_nr_running(p, src_rq);
        set_task_cpu(p, this_cpu);
-       this_rq->nr_running++;
+       inc_nr_running(p, this_rq);
        enqueue_task(p, this_array);
        p->timestamp = (p->timestamp - src_rq->timestamp_last_tick)
                                + this_rq->timestamp_last_tick;
@@ -1853,26 +2018,42 @@ int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
        return 1;
 }
 
+#define rq_best_prio(rq) min((rq)->curr->prio, (rq)->best_expired_prio)
 /*
- * move_tasks tries to move up to max_nr_move tasks from busiest to this_rq,
- * as part of a balancing operation within "domain". Returns the number of
- * tasks moved.
+ * move_tasks tries to move up to max_nr_move tasks and max_load_move weighted
+ * load from busiest to this_rq, as part of a balancing operation within
+ * "domain". Returns the number of tasks moved.
  *
  * Called with both runqueues locked.
  */
 static int move_tasks(runqueue_t *this_rq, int this_cpu, runqueue_t *busiest,
-                     unsigned long max_nr_move, struct sched_domain *sd,
-                     enum idle_type idle, int *all_pinned)
+                     unsigned long max_nr_move, unsigned long max_load_move,
+                     struct sched_domain *sd, enum idle_type idle,
+                     int *all_pinned)
 {
        prio_array_t *array, *dst_array;
        struct list_head *head, *curr;
-       int idx, pulled = 0, pinned = 0;
+       int idx, pulled = 0, pinned = 0, this_best_prio, busiest_best_prio;
+       int busiest_best_prio_seen;
+       int skip_for_load; /* skip the task based on weighted load issues */
+       long rem_load_move;
        task_t *tmp;
 
-       if (max_nr_move == 0)
+       if (max_nr_move == 0 || max_load_move == 0)
                goto out;
 
+       rem_load_move = max_load_move;
        pinned = 1;
+       this_best_prio = rq_best_prio(this_rq);
+       busiest_best_prio = rq_best_prio(busiest);
+       /*
+        * Enable handling of the case where there is more than one task
+        * with the best priority.   If the current running task is one
+        * of those with prio==busiest_best_prio we know it won't be moved
+        * and therefore it's safe to override the skip (based on load) of
+        * any task we find with that prio.
+        */
+       busiest_best_prio_seen = busiest_best_prio == busiest->curr->prio;
 
        /*
         * We first consider expired tasks. Those will likely not be
@@ -1912,7 +2093,17 @@ skip_queue:
 
        curr = curr->prev;
 
-       if (!can_migrate_task(tmp, busiest, this_cpu, sd, idle, &pinned)) {
+       /*
+        * To help distribute high priority tasks accross CPUs we don't
+        * skip a task if it will be the highest priority task (i.e. smallest
+        * prio value) on its new queue regardless of its load weight
+        */
+       skip_for_load = tmp->load_weight > rem_load_move;
+       if (skip_for_load && idx < this_best_prio)
+               skip_for_load = !busiest_best_prio_seen && idx == busiest_best_prio;
+       if (skip_for_load ||
+           !can_migrate_task(tmp, busiest, this_cpu, sd, idle, &pinned)) {
+               busiest_best_prio_seen |= idx == busiest_best_prio;
                if (curr != head)
                        goto skip_queue;
                idx++;
@@ -1926,9 +2117,15 @@ skip_queue:
 
        pull_task(busiest, array, tmp, this_rq, dst_array, this_cpu);
        pulled++;
+       rem_load_move -= tmp->load_weight;
 
-       /* We only want to steal up to the prescribed number of tasks. */
-       if (pulled < max_nr_move) {
+       /*
+        * We only want to steal up to the prescribed number of tasks
+        * and the prescribed amount of weighted load.
+        */
+       if (pulled < max_nr_move && rem_load_move > 0) {
+               if (idx < this_best_prio)
+                       this_best_prio = idx;
                if (curr != head)
                        goto skip_queue;
                idx++;
@@ -1949,7 +2146,7 @@ out:
 
 /*
  * find_busiest_group finds and returns the busiest CPU group within the
- * domain. It calculates and returns the number of tasks which should be
+ * domain. It calculates and returns the amount of weighted load which should be
  * moved to restore balance via the imbalance parameter.
  */
 static struct sched_group *
@@ -1959,9 +2156,19 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
        struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups;
        unsigned long max_load, avg_load, total_load, this_load, total_pwr;
        unsigned long max_pull;
+       unsigned long busiest_load_per_task, busiest_nr_running;
+       unsigned long this_load_per_task, this_nr_running;
        int load_idx;
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+       int power_savings_balance = 1;
+       unsigned long leader_nr_running = 0, min_load_per_task = 0;
+       unsigned long min_nr_running = ULONG_MAX;
+       struct sched_group *group_min = NULL, *group_leader = NULL;
+#endif
 
        max_load = this_load = total_load = total_pwr = 0;
+       busiest_load_per_task = busiest_nr_running = 0;
+       this_load_per_task = this_nr_running = 0;
        if (idle == NOT_IDLE)
                load_idx = sd->busy_idx;
        else if (idle == NEWLY_IDLE)
@@ -1970,16 +2177,19 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                load_idx = sd->idle_idx;
 
        do {
-               unsigned long load;
+               unsigned long load, group_capacity;
                int local_group;
                int i;
+               unsigned long sum_nr_running, sum_weighted_load;
 
                local_group = cpu_isset(this_cpu, group->cpumask);
 
                /* Tally up the load of all CPUs in the group */
-               avg_load = 0;
+               sum_weighted_load = sum_nr_running = avg_load = 0;
 
                for_each_cpu_mask(i, group->cpumask) {
+                       runqueue_t *rq = cpu_rq(i);
+
                        if (*sd_idle && !idle_cpu(i))
                                *sd_idle = 0;
 
@@ -1990,6 +2200,8 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                                load = source_load(i, load_idx);
 
                        avg_load += load;
+                       sum_nr_running += rq->nr_running;
+                       sum_weighted_load += rq->raw_weighted_load;
                }
 
                total_load += avg_load;
@@ -1998,17 +2210,80 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                /* Adjust by relative CPU power of the group */
                avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;
 
+               group_capacity = group->cpu_power / SCHED_LOAD_SCALE;
+
                if (local_group) {
                        this_load = avg_load;
                        this = group;
-               } else if (avg_load > max_load) {
+                       this_nr_running = sum_nr_running;
+                       this_load_per_task = sum_weighted_load;
+               } else if (avg_load > max_load &&
+                          sum_nr_running > group_capacity) {
                        max_load = avg_load;
                        busiest = group;
+                       busiest_nr_running = sum_nr_running;
+                       busiest_load_per_task = sum_weighted_load;
                }
+
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+               /*
+                * Busy processors will not participate in power savings
+                * balance.
+                */
+               if (idle == NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE))
+                       goto group_next;
+
+               /*
+                * If the local group is idle or completely loaded
+                * no need to do power savings balance at this domain
+                */
+               if (local_group && (this_nr_running >= group_capacity ||
+                                   !this_nr_running))
+                       power_savings_balance = 0;
+
+               /*
+                * If a group is already running at full capacity or idle,
+                * don't include that group in power savings calculations
+                */
+               if (!power_savings_balance || sum_nr_running >= group_capacity
+                   || !sum_nr_running)
+                       goto group_next;
+
+               /*
+                * Calculate the group which has the least non-idle load.
+                * This is the group from where we need to pick up the load
+                * for saving power
+                */
+               if ((sum_nr_running < min_nr_running) ||
+                   (sum_nr_running == min_nr_running &&
+                    first_cpu(group->cpumask) <
+                    first_cpu(group_min->cpumask))) {
+                       group_min = group;
+                       min_nr_running = sum_nr_running;
+                       min_load_per_task = sum_weighted_load /
+                                               sum_nr_running;
+               }
+
+               /*
+                * Calculate the group which is almost near its
+                * capacity but still has some space to pick up some load
+                * from other group and save more power
+                */
+               if (sum_nr_running <= group_capacity - 1)
+                       if (sum_nr_running > leader_nr_running ||
+                           (sum_nr_running == leader_nr_running &&
+                            first_cpu(group->cpumask) >
+                             first_cpu(group_leader->cpumask))) {
+                               group_leader = group;
+                               leader_nr_running = sum_nr_running;
+                       }
+
+group_next:
+#endif
                group = group->next;
        } while (group != sd->groups);
 
-       if (!busiest || this_load >= max_load || max_load <= SCHED_LOAD_SCALE)
+       if (!busiest || this_load >= max_load || busiest_nr_running == 0)
                goto out_balanced;
 
        avg_load = (SCHED_LOAD_SCALE * total_load) / total_pwr;
@@ -2017,6 +2292,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                        100*max_load <= sd->imbalance_pct*this_load)
                goto out_balanced;
 
+       busiest_load_per_task /= busiest_nr_running;
        /*
         * We're trying to get all the cpus to the average_load, so we don't
         * want to push ourselves above the average load, nor do we wish to
@@ -2028,21 +2304,50 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
         * by pulling tasks to us.  Be careful of negative numbers as they'll
         * appear as very large values with unsigned longs.
         */
+       if (max_load <= busiest_load_per_task)
+               goto out_balanced;
+
+       /*
+        * In the presence of smp nice balancing, certain scenarios can have
+        * max load less than avg load(as we skip the groups at or below
+        * its cpu_power, while calculating max_load..)
+        */
+       if (max_load < avg_load) {
+               *imbalance = 0;
+               goto small_imbalance;
+       }
 
        /* Don't want to pull so many tasks that a group would go idle */
-       max_pull = min(max_load - avg_load, max_load - SCHED_LOAD_SCALE);
+       max_pull = min(max_load - avg_load, max_load - busiest_load_per_task);
 
        /* How much load to actually move to equalise the imbalance */
        *imbalance = min(max_pull * busiest->cpu_power,
                                (avg_load - this_load) * this->cpu_power)
                        / SCHED_LOAD_SCALE;
 
-       if (*imbalance < SCHED_LOAD_SCALE) {
-               unsigned long pwr_now = 0, pwr_move = 0;
+       /*
+        * if *imbalance is less than the average load per runnable task
+        * there is no gaurantee that any tasks will be moved so we'll have
+        * a think about bumping its value to force at least one task to be
+        * moved
+        */
+       if (*imbalance < busiest_load_per_task) {
+               unsigned long pwr_now, pwr_move;
                unsigned long tmp;
+               unsigned int imbn;
+
+small_imbalance:
+               pwr_move = pwr_now = 0;
+               imbn = 2;
+               if (this_nr_running) {
+                       this_load_per_task /= this_nr_running;
+                       if (busiest_load_per_task > this_load_per_task)
+                               imbn = 1;
+               } else
+                       this_load_per_task = SCHED_LOAD_SCALE;
 
-               if (max_load - this_load >= SCHED_LOAD_SCALE*2) {
-                       *imbalance = 1;
+               if (max_load - this_load >= busiest_load_per_task * imbn) {
+                       *imbalance = busiest_load_per_task;
                        return busiest;
                }
 
@@ -2052,39 +2357,47 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                 * moving them.
                 */
 
-               pwr_now += busiest->cpu_power*min(SCHED_LOAD_SCALE, max_load);
-               pwr_now += this->cpu_power*min(SCHED_LOAD_SCALE, this_load);
+               pwr_now += busiest->cpu_power *
+                       min(busiest_load_per_task, max_load);
+               pwr_now += this->cpu_power *
+                       min(this_load_per_task, this_load);
                pwr_now /= SCHED_LOAD_SCALE;
 
                /* Amount of load we'd subtract */
-               tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/busiest->cpu_power;
+               tmp = busiest_load_per_task*SCHED_LOAD_SCALE/busiest->cpu_power;
                if (max_load > tmp)
-                       pwr_move += busiest->cpu_power*min(SCHED_LOAD_SCALE,
-                                                       max_load - tmp);
+                       pwr_move += busiest->cpu_power *
+                               min(busiest_load_per_task, max_load - tmp);
 
                /* Amount of load we'd add */
                if (max_load*busiest->cpu_power <
-                               SCHED_LOAD_SCALE*SCHED_LOAD_SCALE)
+                               busiest_load_per_task*SCHED_LOAD_SCALE)
                        tmp = max_load*busiest->cpu_power/this->cpu_power;
                else
-                       tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/this->cpu_power;
-               pwr_move += this->cpu_power*min(SCHED_LOAD_SCALE, this_load + tmp);
+                       tmp = busiest_load_per_task*SCHED_LOAD_SCALE/this->cpu_power;
+               pwr_move += this->cpu_power*min(this_load_per_task, this_load + tmp);
                pwr_move /= SCHED_LOAD_SCALE;
 
                /* Move if we gain throughput */
                if (pwr_move <= pwr_now)
                        goto out_balanced;
 
-               *imbalance = 1;
-               return busiest;
+               *imbalance = busiest_load_per_task;
        }
 
-       /* Get rid of the scaling factor, rounding down as we divide */
-       *imbalance = *imbalance / SCHED_LOAD_SCALE;
        return busiest;
 
 out_balanced:
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+       if (idle == NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE))
+               goto ret;
 
+       if (this == group_leader && group_leader != group_min) {
+               *imbalance = min_load_per_task;
+               return group_min;
+       }
+ret:
+#endif
        *imbalance = 0;
        return NULL;
 }
@@ -2093,18 +2406,21 @@ out_balanced:
  * find_busiest_queue - find the busiest runqueue among the cpus in group.
  */
 static runqueue_t *find_busiest_queue(struct sched_group *group,
-       enum idle_type idle)
+       enum idle_type idle, unsigned long imbalance)
 {
-       unsigned long load, max_load = 0;
-       runqueue_t *busiest = NULL;
+       unsigned long max_load = 0;
+       runqueue_t *busiest = NULL, *rqi;
        int i;
 
        for_each_cpu_mask(i, group->cpumask) {
-               load = source_load(i, 0);
+               rqi = cpu_rq(i);
+
+               if (rqi->nr_running == 1 && rqi->raw_weighted_load > imbalance)
+                       continue;
 
-               if (load > max_load) {
-                       max_load = load;
-                       busiest = cpu_rq(i);
+               if (rqi->raw_weighted_load > max_load) {
+                       max_load = rqi->raw_weighted_load;
+                       busiest = rqi;
                }
        }
 
@@ -2117,6 +2433,7 @@ static runqueue_t *find_busiest_queue(struct sched_group *group,
  */
 #define MAX_PINNED_INTERVAL    512
 
+#define minus_1_or_zero(n) ((n) > 0 ? (n) - 1 : 0)
 /*
  * Check this_cpu to ensure it is balanced within domain. Attempt to move
  * tasks if there is an imbalance.
@@ -2133,7 +2450,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
        int active_balance = 0;
        int sd_idle = 0;
 
-       if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER)
+       if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER &&
+           !sched_smt_power_savings)
                sd_idle = 1;
 
        schedstat_inc(sd, lb_cnt[idle]);
@@ -2144,7 +2462,7 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
                goto out_balanced;
        }
 
-       busiest = find_busiest_queue(group, idle);
+       busiest = find_busiest_queue(group, idle, imbalance);
        if (!busiest) {
                schedstat_inc(sd, lb_nobusyq[idle]);
                goto out_balanced;
@@ -2164,6 +2482,7 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
                 */
                double_rq_lock(this_rq, busiest);
                nr_moved = move_tasks(this_rq, this_cpu, busiest,
+                                       minus_1_or_zero(busiest->nr_running),
                                        imbalance, sd, idle, &all_pinned);
                double_rq_unlock(this_rq, busiest);
 
@@ -2221,7 +2540,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
                        sd->balance_interval *= 2;
        }
 
-       if (!nr_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER)
+       if (!nr_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
+           !sched_smt_power_savings)
                return -1;
        return nr_moved;
 
@@ -2236,7 +2556,7 @@ out_one_pinned:
                        (sd->balance_interval < sd->max_interval))
                sd->balance_interval *= 2;
 
-       if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER)
+       if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings)
                return -1;
        return 0;
 }
@@ -2257,7 +2577,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
        int nr_moved = 0;
        int sd_idle = 0;
 
-       if (sd->flags & SD_SHARE_CPUPOWER)
+       if (sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings)
                sd_idle = 1;
 
        schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
@@ -2267,7 +2587,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
                goto out_balanced;
        }
 
-       busiest = find_busiest_queue(group, NEWLY_IDLE);
+       busiest = find_busiest_queue(group, NEWLY_IDLE, imbalance);
        if (!busiest) {
                schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
                goto out_balanced;
@@ -2282,6 +2602,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
                /* Attempt to move tasks */
                double_lock_balance(this_rq, busiest);
                nr_moved = move_tasks(this_rq, this_cpu, busiest,
+                                       minus_1_or_zero(busiest->nr_running),
                                        imbalance, sd, NEWLY_IDLE, NULL);
                spin_unlock(&busiest->lock);
        }
@@ -2297,7 +2618,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
 
 out_balanced:
        schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
-       if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER)
+       if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings)
                return -1;
        sd->nr_balance_failed = 0;
        return 0;
@@ -2352,17 +2673,19 @@ static void active_load_balance(runqueue_t *busiest_rq, int busiest_cpu)
        double_lock_balance(busiest_rq, target_rq);
 
        /* Search for an sd spanning us and the target CPU. */
-       for_each_domain(target_cpu, sd)
+       for_each_domain(target_cpu, sd) {
                if ((sd->flags & SD_LOAD_BALANCE) &&
                        cpu_isset(busiest_cpu, sd->span))
                                break;
+       }
 
        if (unlikely(sd == NULL))
                goto out;
 
        schedstat_inc(sd, alb_cnt);
 
-       if (move_tasks(target_rq, target_cpu, busiest_rq, 1, sd, SCHED_IDLE, NULL))
+       if (move_tasks(target_rq, target_cpu, busiest_rq, 1,
+                       RTPRIO_TO_LOAD_WEIGHT(100), sd, SCHED_IDLE, NULL))
                schedstat_inc(sd, alb_pushed);
        else
                schedstat_inc(sd, alb_failed);
@@ -2390,7 +2713,7 @@ static void rebalance_tick(int this_cpu, runqueue_t *this_rq,
        struct sched_domain *sd;
        int i;
 
-       this_load = this_rq->nr_running * SCHED_LOAD_SCALE;
+       this_load = this_rq->raw_weighted_load;
        /* Update our load */
        for (i = 0; i < 3; i++) {
                unsigned long new_load = this_load;
@@ -2691,48 +3014,35 @@ static inline void wakeup_busy_runqueue(runqueue_t *rq)
                resched_task(rq->idle);
 }
 
-static void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
+/*
+ * Called with interrupt disabled and this_rq's runqueue locked.
+ */
+static void wake_sleeping_dependent(int this_cpu)
 {
        struct sched_domain *tmp, *sd = NULL;
-       cpumask_t sibling_map;
        int i;
 
-       for_each_domain(this_cpu, tmp)
-               if (tmp->flags & SD_SHARE_CPUPOWER)
+       for_each_domain(this_cpu, tmp) {
+               if (tmp->flags & SD_SHARE_CPUPOWER) {
                        sd = tmp;
+                       break;
+               }
+       }
 
        if (!sd)
                return;
 
-       /*
-        * Unlock the current runqueue because we have to lock in
-        * CPU order to avoid deadlocks. Caller knows that we might
-        * unlock. We keep IRQs disabled.
-        */
-       spin_unlock(&this_rq->lock);
-
-       sibling_map = sd->span;
-
-       for_each_cpu_mask(i, sibling_map)
-               spin_lock(&cpu_rq(i)->lock);
-       /*
-        * We clear this CPU from the mask. This both simplifies the
-        * inner loop and keps this_rq locked when we exit:
-        */
-       cpu_clear(this_cpu, sibling_map);
-
-       for_each_cpu_mask(i, sibling_map) {
+       for_each_cpu_mask(i, sd->span) {
                runqueue_t *smt_rq = cpu_rq(i);
 
+               if (i == this_cpu)
+                       continue;
+               if (unlikely(!spin_trylock(&smt_rq->lock)))
+                       continue;
+
                wakeup_busy_runqueue(smt_rq);
+               spin_unlock(&smt_rq->lock);
        }
-
-       for_each_cpu_mask(i, sibling_map)
-               spin_unlock(&cpu_rq(i)->lock);
-       /*
-        * We exit with this_cpu's rq still held and IRQs
-        * still disabled:
-        */
 }
 
 /*
@@ -2745,52 +3055,46 @@ static inline unsigned long smt_slice(task_t *p, struct sched_domain *sd)
        return p->time_slice * (100 - sd->per_cpu_gain) / 100;
 }
 
-static int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
+/*
+ * To minimise lock contention and not have to drop this_rq's runlock we only
+ * trylock the sibling runqueues and bypass those runqueues if we fail to
+ * acquire their lock. As we only trylock the normal locking order does not
+ * need to be obeyed.
+ */
+static int dependent_sleeper(int this_cpu, runqueue_t *this_rq, task_t *p)
 {
        struct sched_domain *tmp, *sd = NULL;
-       cpumask_t sibling_map;
-       prio_array_t *array;
        int ret = 0, i;
-       task_t *p;
 
-       for_each_domain(this_cpu, tmp)
-               if (tmp->flags & SD_SHARE_CPUPOWER)
+       /* kernel/rt threads do not participate in dependent sleeping */
+       if (!p->mm || rt_task(p))
+               return 0;
+
+       for_each_domain(this_cpu, tmp) {
+               if (tmp->flags & SD_SHARE_CPUPOWER) {
                        sd = tmp;
+                       break;
+               }
+       }
 
        if (!sd)
                return 0;
 
-       /*
-        * The same locking rules and details apply as for
-        * wake_sleeping_dependent():
-        */
-       spin_unlock(&this_rq->lock);
-       sibling_map = sd->span;
-       for_each_cpu_mask(i, sibling_map)
-               spin_lock(&cpu_rq(i)->lock);
-       cpu_clear(this_cpu, sibling_map);
+       for_each_cpu_mask(i, sd->span) {
+               runqueue_t *smt_rq;
+               task_t *smt_curr;
 
-       /*
-        * Establish next task to be run - it might have gone away because
-        * we released the runqueue lock above:
-        */
-       if (!this_rq->nr_running)
-               goto out_unlock;
-       array = this_rq->active;
-       if (!array->nr_active)
-               array = this_rq->expired;
-       BUG_ON(!array->nr_active);
+               if (i == this_cpu)
+                       continue;
 
-       p = list_entry(array->queue[sched_find_first_bit(array->bitmap)].next,
-               task_t, run_list);
+               smt_rq = cpu_rq(i);
+               if (unlikely(!spin_trylock(&smt_rq->lock)))
+                       continue;
 
-       for_each_cpu_mask(i, sibling_map) {
-               runqueue_t *smt_rq = cpu_rq(i);
-               task_t *smt_curr = smt_rq->curr;
+               smt_curr = smt_rq->curr;
 
-               /* Kernel threads do not participate in dependent sleeping */
-               if (!p->mm || !smt_curr->mm || rt_task(p))
-                       goto check_smt_task;
+               if (!smt_curr->mm)
+                       goto unlock;
 
                /*
                 * If a user task with lower static priority than the
@@ -2808,49 +3112,24 @@ static int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
                        if ((jiffies % DEF_TIMESLICE) >
                                (sd->per_cpu_gain * DEF_TIMESLICE / 100))
                                        ret = 1;
-               } else
+               } else {
                        if (smt_curr->static_prio < p->static_prio &&
                                !TASK_PREEMPTS_CURR(p, smt_rq) &&
                                smt_slice(smt_curr, sd) > task_timeslice(p))
                                        ret = 1;
-
-check_smt_task:
-               if ((!smt_curr->mm && smt_curr != smt_rq->idle) ||
-                       rt_task(smt_curr))
-                               continue;
-               if (!p->mm) {
-                       wakeup_busy_runqueue(smt_rq);
-                       continue;
-               }
-
-               /*
-                * Reschedule a lower priority task on the SMT sibling for
-                * it to be put to sleep, or wake it up if it has been put to
-                * sleep for priority reasons to see if it should run now.
-                */
-               if (rt_task(p)) {
-                       if ((jiffies % DEF_TIMESLICE) >
-                               (sd->per_cpu_gain * DEF_TIMESLICE / 100))
-                                       resched_task(smt_curr);
-               } else {
-                       if (TASK_PREEMPTS_CURR(p, smt_rq) &&
-                               smt_slice(p, sd) > task_timeslice(smt_curr))
-                                       resched_task(smt_curr);
-                       else
-                               wakeup_busy_runqueue(smt_rq);
                }
+unlock:
+               spin_unlock(&smt_rq->lock);
        }
-out_unlock:
-       for_each_cpu_mask(i, sibling_map)
-               spin_unlock(&cpu_rq(i)->lock);
        return ret;
 }
 #else
-static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
+static inline void wake_sleeping_dependent(int this_cpu)
 {
 }
 
-static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
+static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq,
+                                       task_t *p)
 {
        return 0;
 }
@@ -2972,32 +3251,13 @@ need_resched_nonpreemptible:
 
        cpu = smp_processor_id();
        if (unlikely(!rq->nr_running)) {
-go_idle:
                idle_balance(cpu, rq);
                if (!rq->nr_running) {
                        next = rq->idle;
                        rq->expired_timestamp = 0;
-                       wake_sleeping_dependent(cpu, rq);
-                       /*
-                        * wake_sleeping_dependent() might have released
-                        * the runqueue, so break out if we got new
-                        * tasks meanwhile:
-                        */
-                       if (!rq->nr_running)
-                               goto switch_tasks;
-               }
-       } else {
-               if (dependent_sleeper(cpu, rq)) {
-                       next = rq->idle;
+                       wake_sleeping_dependent(cpu);
                        goto switch_tasks;
                }
-               /*
-                * dependent_sleeper() releases and reacquires the runqueue
-                * lock, hence go into the idle loop if the rq went
-                * empty meanwhile:
-                */
-               if (unlikely(!rq->nr_running))
-                       goto go_idle;
        }
 
        array = rq->active;
@@ -3035,6 +3295,8 @@ go_idle:
                }
        }
        next->sleep_type = SLEEP_NORMAL;
+       if (dependent_sleeper(cpu, rq, next))
+               next = rq->idle;
 switch_tasks:
        if (next == rq->idle)
                schedstat_inc(rq, sched_goidle);
@@ -3478,12 +3740,65 @@ long fastcall __sched sleep_on_timeout(wait_queue_head_t *q, long timeout)
 
 EXPORT_SYMBOL(sleep_on_timeout);
 
+#ifdef CONFIG_RT_MUTEXES
+
+/*
+ * rt_mutex_setprio - set the current priority of a task
+ * @p: task
+ * @prio: prio value (kernel-internal form)
+ *
+ * This function changes the 'effective' priority of a task. It does
+ * not touch ->normal_prio like __setscheduler().
+ *
+ * Used by the rt_mutex code to implement priority inheritance logic.
+ */
+void rt_mutex_setprio(task_t *p, int prio)
+{
+       unsigned long flags;
+       prio_array_t *array;
+       runqueue_t *rq;
+       int oldprio;
+
+       BUG_ON(prio < 0 || prio > MAX_PRIO);
+
+       rq = task_rq_lock(p, &flags);
+
+       oldprio = p->prio;
+       array = p->array;
+       if (array)
+               dequeue_task(p, array);
+       p->prio = prio;
+
+       if (array) {
+               /*
+                * If changing to an RT priority then queue it
+                * in the active array!
+                */
+               if (rt_task(p))
+                       array = rq->active;
+               enqueue_task(p, array);
+               /*
+                * Reschedule if we are currently running on this runqueue and
+                * our priority decreased, or if we are not currently running on
+                * this runqueue and our priority is higher than the current's
+                */
+               if (task_running(rq, p)) {
+                       if (p->prio > oldprio)
+                               resched_task(rq->curr);
+               } else if (TASK_PREEMPTS_CURR(p, rq))
+                       resched_task(rq->curr);
+       }
+       task_rq_unlock(rq, &flags);
+}
+
+#endif
+
 void set_user_nice(task_t *p, long nice)
 {
        unsigned long flags;
        prio_array_t *array;
        runqueue_t *rq;
-       int old_prio, new_prio, delta;
+       int old_prio, delta;
 
        if (TASK_NICE(p) == nice || nice < -20 || nice > 19)
                return;
@@ -3498,22 +3813,25 @@ void set_user_nice(task_t *p, long nice)
         * it wont have any effect on scheduling until the task is
         * not SCHED_NORMAL/SCHED_BATCH:
         */
-       if (rt_task(p)) {
+       if (has_rt_policy(p)) {
                p->static_prio = NICE_TO_PRIO(nice);
                goto out_unlock;
        }
        array = p->array;
-       if (array)
+       if (array) {
                dequeue_task(p, array);
+               dec_raw_weighted_load(rq, p);
+       }
 
-       old_prio = p->prio;
-       new_prio = NICE_TO_PRIO(nice);
-       delta = new_prio - old_prio;
        p->static_prio = NICE_TO_PRIO(nice);
-       p->prio += delta;
+       set_load_weight(p);
+       old_prio = p->prio;
+       p->prio = effective_prio(p);
+       delta = p->prio - old_prio;
 
        if (array) {
                enqueue_task(p, array);
+               inc_raw_weighted_load(rq, p);
                /*
                 * If the task increased its priority or is running and
                 * lowered its priority, then reschedule its CPU:
@@ -3524,7 +3842,6 @@ void set_user_nice(task_t *p, long nice)
 out_unlock:
        task_rq_unlock(rq, &flags);
 }
-
 EXPORT_SYMBOL(set_user_nice);
 
 /*
@@ -3639,16 +3956,15 @@ static void __setscheduler(struct task_struct *p, int policy, int prio)
        BUG_ON(p->array);
        p->policy = policy;
        p->rt_priority = prio;
-       if (policy != SCHED_NORMAL && policy != SCHED_BATCH) {
-               p->prio = MAX_RT_PRIO-1 - p->rt_priority;
-       } else {
-               p->prio = p->static_prio;
-               /*
-                * SCHED_BATCH tasks are treated as perpetual CPU hogs:
-                */
-               if (policy == SCHED_BATCH)
-                       p->sleep_avg = 0;
-       }
+       p->normal_prio = normal_prio(p);
+       /* we are holding p->pi_lock already */
+       p->prio = rt_mutex_getprio(p);
+       /*
+        * SCHED_BATCH tasks are treated as perpetual CPU hogs:
+        */
+       if (policy == SCHED_BATCH)
+               p->sleep_avg = 0;
+       set_load_weight(p);
 }
 
 /**
@@ -3667,6 +3983,8 @@ int sched_setscheduler(struct task_struct *p, int policy,
        unsigned long flags;
        runqueue_t *rq;
 
+       /* may grab non-irq protected spin_locks */
+       BUG_ON(in_interrupt());
 recheck:
        /* double check policy once rq lock held */
        if (policy < 0)
@@ -3714,15 +4032,21 @@ recheck:
        retval = security_task_setscheduler(p, policy, param);
        if (retval)
                return retval;
+       /*
+        * make sure no PI-waiters arrive (or leave) while we are
+        * changing the priority of the task:
+        */
+       spin_lock_irqsave(&p->pi_lock, flags);
        /*
         * To be able to change p->policy safely, the apropriate
         * runqueue lock must be held.
         */
-       rq = task_rq_lock(p, &flags);
+       rq = __task_rq_lock(p);
        /* recheck policy now with rq lock held */
        if (unlikely(oldpolicy != -1 && oldpolicy != p->policy)) {
                policy = oldpolicy = -1;
-               task_rq_unlock(rq, &flags);
+               __task_rq_unlock(rq);
+               spin_unlock_irqrestore(&p->pi_lock, flags);
                goto recheck;
        }
        array = p->array;
@@ -3743,7 +4067,11 @@ recheck:
                } else if (TASK_PREEMPTS_CURR(p, rq))
                        resched_task(rq->curr);
        }
-       task_rq_unlock(rq, &flags);
+       __task_rq_unlock(rq);
+       spin_unlock_irqrestore(&p->pi_lock, flags);
+
+       rt_mutex_adjust_pi(p);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(sched_setscheduler);
@@ -3765,8 +4093,10 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
                read_unlock_irq(&tasklist_lock);
                return -ESRCH;
        }
-       retval = sched_setscheduler(p, policy, &lparam);
+       get_task_struct(p);
        read_unlock_irq(&tasklist_lock);
+       retval = sched_setscheduler(p, policy, &lparam);
+       put_task_struct(p);
        return retval;
 }
 
@@ -4378,7 +4708,7 @@ void __devinit init_idle(task_t *idle, int cpu)
        idle->timestamp = sched_clock();
        idle->sleep_avg = 0;
        idle->array = NULL;
-       idle->prio = MAX_PRIO;
+       idle->prio = idle->normal_prio = MAX_PRIO;
        idle->state = TASK_RUNNING;
        idle->cpus_allowed = cpumask_of_cpu(cpu);
        set_task_cpu(idle, cpu);
@@ -4474,13 +4804,16 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed);
  *
  * So we race with normal scheduler movements, but that's OK, as long
  * as the task is no longer on this CPU.
+ *
+ * Returns non-zero if task was successfully migrated.
  */
-static void __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
+static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
 {
        runqueue_t *rq_dest, *rq_src;
+       int ret = 0;
 
        if (unlikely(cpu_is_offline(dest_cpu)))
-               return;
+               return ret;
 
        rq_src = cpu_rq(src_cpu);
        rq_dest = cpu_rq(dest_cpu);
@@ -4508,9 +4841,10 @@ static void __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
                if (TASK_PREEMPTS_CURR(p, rq_dest))
                        resched_task(rq_dest->curr);
        }
-
+       ret = 1;
 out:
        double_rq_unlock(rq_src, rq_dest);
+       return ret;
 }
 
 /*
@@ -4580,9 +4914,12 @@ wait_to_die:
 /* Figure out where task on dead CPU should go, use force if neccessary. */
 static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk)
 {
+       runqueue_t *rq;
+       unsigned long flags;
        int dest_cpu;
        cpumask_t mask;
 
+restart:
        /* On same node? */
        mask = node_to_cpumask(cpu_to_node(dead_cpu));
        cpus_and(mask, mask, tsk->cpus_allowed);
@@ -4594,8 +4931,10 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk)
 
        /* No more Mr. Nice Guy. */
        if (dest_cpu == NR_CPUS) {
+               rq = task_rq_lock(tsk, &flags);
                cpus_setall(tsk->cpus_allowed);
                dest_cpu = any_online_cpu(tsk->cpus_allowed);
+               task_rq_unlock(rq, &flags);
 
                /*
                 * Don't tell them about moving exiting tasks or
@@ -4607,7 +4946,8 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk)
                               "longer affine to cpu%d\n",
                               tsk->pid, tsk->comm, dead_cpu);
        }
-       __migrate_task(tsk, dead_cpu, dest_cpu);
+       if (!__migrate_task(tsk, dead_cpu, dest_cpu))
+               goto restart;
 }
 
 /*
@@ -4734,8 +5074,9 @@ static void migrate_dead_tasks(unsigned int dead_cpu)
  * migration_call - callback that gets triggered when a CPU is added.
  * Here we can start up the necessary migration thread for the new CPU.
  */
-static int migration_call(struct notifier_block *nfb, unsigned long action,
-                         void *hcpu)
+static int __cpuinit migration_call(struct notifier_block *nfb,
+                       unsigned long action,
+                       void *hcpu)
 {
        int cpu = (long)hcpu;
        struct task_struct *p;
@@ -4805,7 +5146,7 @@ static int migration_call(struct notifier_block *nfb, unsigned long action,
 /* Register at highest priority so that task migration (migrate_all_tasks)
  * happens before everything else.
  */
-static struct notifier_block migration_notifier = {
+static struct notifier_block __cpuinitdata migration_notifier = {
        .notifier_call = migration_call,
        .priority = 10
 };
@@ -5606,6 +5947,7 @@ static cpumask_t sched_domain_node_span(int node)
 }
 #endif
 
+int sched_smt_power_savings = 0, sched_mc_power_savings = 0;
 /*
  * At the moment, CONFIG_SCHED_SMT is never defined, but leave it in so we
  * can switch it on easily if needed.
@@ -5621,7 +5963,7 @@ static int cpu_to_cpu_group(int cpu)
 
 #ifdef CONFIG_SCHED_MC
 static DEFINE_PER_CPU(struct sched_domain, core_domains);
-static struct sched_group sched_group_core[NR_CPUS];
+static struct sched_group *sched_group_core_bycpu[NR_CPUS];
 #endif
 
 #if defined(CONFIG_SCHED_MC) && defined(CONFIG_SCHED_SMT)
@@ -5637,7 +5979,7 @@ static int cpu_to_core_group(int cpu)
 #endif
 
 static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-static struct sched_group sched_group_phys[NR_CPUS];
+static struct sched_group *sched_group_phys_bycpu[NR_CPUS];
 static int cpu_to_phys_group(int cpu)
 {
 #if defined(CONFIG_SCHED_MC)
@@ -5694,13 +6036,74 @@ next_sg:
 }
 #endif
 
+/* Free memory allocated for various sched_group structures */
+static void free_sched_groups(const cpumask_t *cpu_map)
+{
+       int cpu;
+#ifdef CONFIG_NUMA
+       int i;
+
+       for_each_cpu_mask(cpu, *cpu_map) {
+               struct sched_group *sched_group_allnodes
+                       = sched_group_allnodes_bycpu[cpu];
+               struct sched_group **sched_group_nodes
+                       = sched_group_nodes_bycpu[cpu];
+
+               if (sched_group_allnodes) {
+                       kfree(sched_group_allnodes);
+                       sched_group_allnodes_bycpu[cpu] = NULL;
+               }
+
+               if (!sched_group_nodes)
+                       continue;
+
+               for (i = 0; i < MAX_NUMNODES; i++) {
+                       cpumask_t nodemask = node_to_cpumask(i);
+                       struct sched_group *oldsg, *sg = sched_group_nodes[i];
+
+                       cpus_and(nodemask, nodemask, *cpu_map);
+                       if (cpus_empty(nodemask))
+                               continue;
+
+                       if (sg == NULL)
+                               continue;
+                       sg = sg->next;
+next_sg:
+                       oldsg = sg;
+                       sg = sg->next;
+                       kfree(oldsg);
+                       if (oldsg != sched_group_nodes[i])
+                               goto next_sg;
+               }
+               kfree(sched_group_nodes);
+               sched_group_nodes_bycpu[cpu] = NULL;
+       }
+#endif
+       for_each_cpu_mask(cpu, *cpu_map) {
+               if (sched_group_phys_bycpu[cpu]) {
+                       kfree(sched_group_phys_bycpu[cpu]);
+                       sched_group_phys_bycpu[cpu] = NULL;
+               }
+#ifdef CONFIG_SCHED_MC
+               if (sched_group_core_bycpu[cpu]) {
+                       kfree(sched_group_core_bycpu[cpu]);
+                       sched_group_core_bycpu[cpu] = NULL;
+               }
+#endif
+       }
+}
+
 /*
  * Build sched domains for a given set of cpus and attach the sched domains
  * to the individual cpus
  */
-void build_sched_domains(const cpumask_t *cpu_map)
+static int build_sched_domains(const cpumask_t *cpu_map)
 {
        int i;
+       struct sched_group *sched_group_phys = NULL;
+#ifdef CONFIG_SCHED_MC
+       struct sched_group *sched_group_core = NULL;
+#endif
 #ifdef CONFIG_NUMA
        struct sched_group **sched_group_nodes = NULL;
        struct sched_group *sched_group_allnodes = NULL;
@@ -5708,11 +6111,11 @@ void build_sched_domains(const cpumask_t *cpu_map)
        /*
         * Allocate the per-node list of sched groups
         */
-       sched_group_nodes = kmalloc(sizeof(struct sched_group*)*MAX_NUMNODES,
-                                          GFP_ATOMIC);
+       sched_group_nodes = kzalloc(sizeof(struct sched_group*)*MAX_NUMNODES,
+                                          GFP_KERNEL);
        if (!sched_group_nodes) {
                printk(KERN_WARNING "Can not alloc sched group node list\n");
-               return;
+               return -ENOMEM;
        }
        sched_group_nodes_bycpu[first_cpu(*cpu_map)] = sched_group_nodes;
 #endif
@@ -5738,7 +6141,7 @@ void build_sched_domains(const cpumask_t *cpu_map)
                                if (!sched_group_allnodes) {
                                        printk(KERN_WARNING
                                        "Can not alloc allnodes sched group\n");
-                                       break;
+                                       goto error;
                                }
                                sched_group_allnodes_bycpu[i]
                                                = sched_group_allnodes;
@@ -5759,6 +6162,18 @@ void build_sched_domains(const cpumask_t *cpu_map)
                cpus_and(sd->span, sd->span, *cpu_map);
 #endif
 
+               if (!sched_group_phys) {
+                       sched_group_phys
+                               = kmalloc(sizeof(struct sched_group) * NR_CPUS,
+                                         GFP_KERNEL);
+                       if (!sched_group_phys) {
+                               printk (KERN_WARNING "Can not alloc phys sched"
+                                                    "group\n");
+                               goto error;
+                       }
+                       sched_group_phys_bycpu[i] = sched_group_phys;
+               }
+
                p = sd;
                sd = &per_cpu(phys_domains, i);
                group = cpu_to_phys_group(i);
@@ -5768,6 +6183,18 @@ void build_sched_domains(const cpumask_t *cpu_map)
                sd->groups = &sched_group_phys[group];
 
 #ifdef CONFIG_SCHED_MC
+               if (!sched_group_core) {
+                       sched_group_core
+                               = kmalloc(sizeof(struct sched_group) * NR_CPUS,
+                                         GFP_KERNEL);
+                       if (!sched_group_core) {
+                               printk (KERN_WARNING "Can not alloc core sched"
+                                                    "group\n");
+                               goto error;
+                       }
+                       sched_group_core_bycpu[i] = sched_group_core;
+               }
+
                p = sd;
                sd = &per_cpu(core_domains, i);
                group = cpu_to_core_group(i);
@@ -5851,24 +6278,21 @@ void build_sched_domains(const cpumask_t *cpu_map)
                domainspan = sched_domain_node_span(i);
                cpus_and(domainspan, domainspan, *cpu_map);
 
-               sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
+               sg = kmalloc_node(sizeof(struct sched_group), GFP_KERNEL, i);
+               if (!sg) {
+                       printk(KERN_WARNING "Can not alloc domain group for "
+                               "node %d\n", i);
+                       goto error;
+               }
                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;
+               sg->next = sg;
                cpus_or(covered, covered, nodemask);
                prev = sg;
 
@@ -5887,54 +6311,90 @@ void build_sched_domains(const cpumask_t *cpu_map)
                        if (cpus_empty(tmp))
                                continue;
 
-                       sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
+                       sg = kmalloc_node(sizeof(struct sched_group),
+                                         GFP_KERNEL, i);
                        if (!sg) {
                                printk(KERN_WARNING
                                "Can not alloc domain group for node %d\n", j);
-                               break;
+                               goto error;
                        }
                        sg->cpu_power = 0;
                        sg->cpumask = tmp;
+                       sg->next = prev->next;
                        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 */
+#ifdef CONFIG_SCHED_SMT
        for_each_cpu_mask(i, *cpu_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;
+               sd->groups->cpu_power = SCHED_LOAD_SCALE;
+       }
 #endif
 #ifdef CONFIG_SCHED_MC
+       for_each_cpu_mask(i, *cpu_map) {
+               int power;
+               struct sched_domain *sd;
                sd = &per_cpu(core_domains, i);
-               power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1)
+               if (sched_smt_power_savings)
+                       power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask);
+               else
+                       power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1)
                                            * SCHED_LOAD_SCALE / 10;
                sd->groups->cpu_power = power;
+       }
+#endif
 
+       for_each_cpu_mask(i, *cpu_map) {
+               struct sched_domain *sd;
+#ifdef CONFIG_SCHED_MC
                sd = &per_cpu(phys_domains, i);
+               if (i != first_cpu(sd->groups->cpumask))
+                       continue;
 
-               /*
-                * This has to be < 2 * SCHED_LOAD_SCALE
-                * Lets keep it SCHED_LOAD_SCALE, so that
-                * while calculating NUMA group's cpu_power
-                * we can simply do
-                *  numa_group->cpu_power += phys_group->cpu_power;
-                *
-                * See "only add power once for each physical pkg"
-                * comment below
-                */
-               sd->groups->cpu_power = SCHED_LOAD_SCALE;
+               sd->groups->cpu_power = 0;
+               if (sched_mc_power_savings || sched_smt_power_savings) {
+                       int j;
+
+                       for_each_cpu_mask(j, sd->groups->cpumask) {
+                               struct sched_domain *sd1;
+                               sd1 = &per_cpu(core_domains, j);
+                               /*
+                                * for each core we will add once
+                                * to the group in physical domain
+                                */
+                               if (j != first_cpu(sd1->groups->cpumask))
+                                       continue;
+
+                               if (sched_smt_power_savings)
+                                       sd->groups->cpu_power += sd1->groups->cpu_power;
+                               else
+                                       sd->groups->cpu_power += SCHED_LOAD_SCALE;
+                       }
+               } else
+                       /*
+                        * This has to be < 2 * SCHED_LOAD_SCALE
+                        * Lets keep it SCHED_LOAD_SCALE, so that
+                        * while calculating NUMA group's cpu_power
+                        * we can simply do
+                        *  numa_group->cpu_power += phys_group->cpu_power;
+                        *
+                        * See "only add power once for each physical pkg"
+                        * comment below
+                        */
+                       sd->groups->cpu_power = SCHED_LOAD_SCALE;
 #else
+               int power;
                sd = &per_cpu(phys_domains, i);
-               power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
-                               (cpus_weight(sd->groups->cpumask)-1) / 10;
+               if (sched_smt_power_savings)
+                       power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask);
+               else
+                       power = SCHED_LOAD_SCALE;
                sd->groups->cpu_power = power;
 #endif
        }
@@ -5962,13 +6422,20 @@ void build_sched_domains(const cpumask_t *cpu_map)
         * Tune cache-hot values:
         */
        calibrate_migration_costs(cpu_map);
+
+       return 0;
+
+error:
+       free_sched_groups(cpu_map);
+       return -ENOMEM;
 }
 /*
  * Set up scheduler domains and groups.  Callers must hold the hotplug lock.
  */
-static void arch_init_sched_domains(const cpumask_t *cpu_map)
+static int arch_init_sched_domains(const cpumask_t *cpu_map)
 {
        cpumask_t cpu_default_map;
+       int err;
 
        /*
         * Setup mask for cpus without special case scheduling requirements.
@@ -5977,51 +6444,14 @@ static void arch_init_sched_domains(const cpumask_t *cpu_map)
         */
        cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map);
 
-       build_sched_domains(&cpu_default_map);
+       err = build_sched_domains(&cpu_default_map);
+
+       return err;
 }
 
 static void arch_destroy_sched_domains(const cpumask_t *cpu_map)
 {
-#ifdef CONFIG_NUMA
-       int i;
-       int cpu;
-
-       for_each_cpu_mask(cpu, *cpu_map) {
-               struct sched_group *sched_group_allnodes
-                       = sched_group_allnodes_bycpu[cpu];
-               struct sched_group **sched_group_nodes
-                       = sched_group_nodes_bycpu[cpu];
-
-               if (sched_group_allnodes) {
-                       kfree(sched_group_allnodes);
-                       sched_group_allnodes_bycpu[cpu] = NULL;
-               }
-
-               if (!sched_group_nodes)
-                       continue;
-
-               for (i = 0; i < MAX_NUMNODES; i++) {
-                       cpumask_t nodemask = node_to_cpumask(i);
-                       struct sched_group *oldsg, *sg = sched_group_nodes[i];
-
-                       cpus_and(nodemask, nodemask, *cpu_map);
-                       if (cpus_empty(nodemask))
-                               continue;
-
-                       if (sg == NULL)
-                               continue;
-                       sg = sg->next;
-next_sg:
-                       oldsg = sg;
-                       sg = sg->next;
-                       kfree(oldsg);
-                       if (oldsg != sched_group_nodes[i])
-                               goto next_sg;
-               }
-               kfree(sched_group_nodes);
-               sched_group_nodes_bycpu[cpu] = NULL;
-       }
-#endif
+       free_sched_groups(cpu_map);
 }
 
 /*
@@ -6046,9 +6476,10 @@ static void detach_destroy_domains(const cpumask_t *cpu_map)
  * correct sched domains
  * Call with hotplug lock held
  */
-void partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
+int partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
 {
        cpumask_t change_map;
+       int err = 0;
 
        cpus_and(*partition1, *partition1, cpu_online_map);
        cpus_and(*partition2, *partition2, cpu_online_map);
@@ -6057,10 +6488,86 @@ void partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
        /* Detach sched domains from all of the affected cpus */
        detach_destroy_domains(&change_map);
        if (!cpus_empty(*partition1))
-               build_sched_domains(partition1);
-       if (!cpus_empty(*partition2))
-               build_sched_domains(partition2);
+               err = build_sched_domains(partition1);
+       if (!err && !cpus_empty(*partition2))
+               err = build_sched_domains(partition2);
+
+       return err;
+}
+
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+int arch_reinit_sched_domains(void)
+{
+       int err;
+
+       lock_cpu_hotplug();
+       detach_destroy_domains(&cpu_online_map);
+       err = arch_init_sched_domains(&cpu_online_map);
+       unlock_cpu_hotplug();
+
+       return err;
+}
+
+static ssize_t sched_power_savings_store(const char *buf, size_t count, int smt)
+{
+       int ret;
+
+       if (buf[0] != '0' && buf[0] != '1')
+               return -EINVAL;
+
+       if (smt)
+               sched_smt_power_savings = (buf[0] == '1');
+       else
+               sched_mc_power_savings = (buf[0] == '1');
+
+       ret = arch_reinit_sched_domains();
+
+       return ret ? ret : count;
+}
+
+int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls)
+{
+       int err = 0;
+#ifdef CONFIG_SCHED_SMT
+       if (smt_capable())
+               err = sysfs_create_file(&cls->kset.kobj,
+                                       &attr_sched_smt_power_savings.attr);
+#endif
+#ifdef CONFIG_SCHED_MC
+       if (!err && mc_capable())
+               err = sysfs_create_file(&cls->kset.kobj,
+                                       &attr_sched_mc_power_savings.attr);
+#endif
+       return err;
+}
+#endif
+
+#ifdef CONFIG_SCHED_MC
+static ssize_t sched_mc_power_savings_show(struct sys_device *dev, char *page)
+{
+       return sprintf(page, "%u\n", sched_mc_power_savings);
+}
+static ssize_t sched_mc_power_savings_store(struct sys_device *dev, const char *buf, size_t count)
+{
+       return sched_power_savings_store(buf, count, 0);
+}
+SYSDEV_ATTR(sched_mc_power_savings, 0644, sched_mc_power_savings_show,
+           sched_mc_power_savings_store);
+#endif
+
+#ifdef CONFIG_SCHED_SMT
+static ssize_t sched_smt_power_savings_show(struct sys_device *dev, char *page)
+{
+       return sprintf(page, "%u\n", sched_smt_power_savings);
+}
+static ssize_t sched_smt_power_savings_store(struct sys_device *dev, const char *buf, size_t count)
+{
+       return sched_power_savings_store(buf, count, 1);
 }
+SYSDEV_ATTR(sched_smt_power_savings, 0644, sched_smt_power_savings_show,
+           sched_smt_power_savings_store);
+#endif
+
 
 #ifdef CONFIG_HOTPLUG_CPU
 /*
@@ -6143,7 +6650,6 @@ void __init sched_init(void)
                rq->push_cpu = 0;
                rq->migration_thread = NULL;
                INIT_LIST_HEAD(&rq->migration_queue);
-               rq->cpu = i;
 #endif
                atomic_set(&rq->nr_iowait, 0);
 
@@ -6158,6 +6664,7 @@ void __init sched_init(void)
                }
        }
 
+       set_load_weight(&init_task);
        /*
         * The boot idle thread does lazy MMU switching as well:
         */
@@ -6204,11 +6711,12 @@ void normalize_rt_tasks(void)
        runqueue_t *rq;
 
        read_lock_irq(&tasklist_lock);
-       for_each_process (p) {
+       for_each_process(p) {
                if (!rt_task(p))
                        continue;
 
-               rq = task_rq_lock(p, &flags);
+               spin_lock_irqsave(&p->pi_lock, flags);
+               rq = __task_rq_lock(p);
 
                array = p->array;
                if (array)
@@ -6219,7 +6727,8 @@ void normalize_rt_tasks(void)
                        resched_task(rq->curr);
                }
 
-               task_rq_unlock(rq, &flags);
+               __task_rq_unlock(rq);
+               spin_unlock_irqrestore(&p->pi_lock, flags);
        }
        read_unlock_irq(&tasklist_lock);
 }
index 9e2f1c6e73d7b341958c74baa8af54169c88c119..8f03e3b89b5540a0e21b1bab99dcb455bb74ffd5 100644 (file)
@@ -446,7 +446,7 @@ static void takeover_tasklets(unsigned int cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static int cpu_callback(struct notifier_block *nfb,
+static int __devinit cpu_callback(struct notifier_block *nfb,
                                  unsigned long action,
                                  void *hcpu)
 {
@@ -486,7 +486,7 @@ static int cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpu_nfb = {
+static struct notifier_block __devinitdata cpu_nfb = {
        .notifier_call = cpu_callback
 };
 
index b5c3b94e01ce7408a9f3d0dae310cff0a6939a36..6b76caa229818811f61aaacf16afd9c2b6da5dc5 100644 (file)
@@ -104,7 +104,7 @@ static int watchdog(void * __bind_cpu)
 /*
  * Create/destroy watchdog threads as CPUs come and go:
  */
-static int
+static int __devinit
 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
@@ -142,7 +142,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpu_nfb = {
+static struct notifier_block __devinitdata cpu_nfb = {
        .notifier_call = cpu_callback
 };
 
index f1a4eb1a655e31a8a44800f5e6a8ecdd87065071..93a2c53986488f5c29cf05318db80241118bda74 100644 (file)
@@ -133,6 +133,10 @@ extern int acct_parm[];
 extern int no_unaligned_warning;
 #endif
 
+#ifdef CONFIG_RT_MUTEXES
+extern int max_lock_depth;
+#endif
+
 static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t,
                       ctl_table *, void **);
 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
@@ -688,6 +692,17 @@ static ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
 #endif
+#ifdef CONFIG_RT_MUTEXES
+       {
+               .ctl_name       = KERN_MAX_LOCK_DEPTH,
+               .procname       = "max_lock_depth",
+               .data           = &max_lock_depth,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
+
        { .ctl_name = 0 }
 };
 
@@ -927,6 +942,18 @@ static ctl_table vm_table[] = {
                .proc_handler   = &proc_dointvec_jiffies,
                .strategy       = &sysctl_jiffies,
        },
+#endif
+#ifdef CONFIG_X86_32
+       {
+               .ctl_name       = VM_VDSO_ENABLED,
+               .procname       = "vdso_enabled",
+               .data           = &vdso_enabled,
+               .maxlen         = sizeof(vdso_enabled),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+       },
 #endif
        { .ctl_name = 0 }
 };
index 5bb6b7976eecf6c215b561b42b4d79c4197507eb..5a8960253063d00495366a48d92e06e5eb4133fa 100644 (file)
@@ -1652,7 +1652,7 @@ static void __devinit migrate_timers(int cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static int timer_cpu_notify(struct notifier_block *self,
+static int __devinit timer_cpu_notify(struct notifier_block *self,
                                unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
@@ -1672,7 +1672,7 @@ static int timer_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block timers_nb = {
+static struct notifier_block __devinitdata timers_nb = {
        .notifier_call  = timer_cpu_notify,
 };
 
index 565cf7a1febda94b88582c6e9326d782fb29f96c..59f0b42bd89e0e819a1a67145f48a11f2898bbd2 100644 (file)
@@ -559,7 +559,7 @@ static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
 }
 
 /* We're holding the cpucontrol mutex here */
-static int workqueue_cpu_callback(struct notifier_block *nfb,
+static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
                                  unsigned long action,
                                  void *hcpu)
 {
index 3de93357f5ab1e05c370164e5e390eb7d0595f9f..f6299342b882d86f56b70655879b5c8ba792f3d4 100644 (file)
@@ -86,4 +86,10 @@ config TEXTSEARCH_BM
 config TEXTSEARCH_FSM
        tristate
 
+#
+# plist support is select#ed if needed
+#
+config PLIST
+       boolean
+
 endmenu
index 8bab0102ac739d181bbddc7fc5a14f2d562353c3..e4fcbd12cf6ef75b75d7eebc40d1b45de3a22236 100644 (file)
@@ -23,6 +23,22 @@ config MAGIC_SYSRQ
          keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
          unless you really know what this hack does.
 
+config UNUSED_SYMBOLS
+       bool "Enable unused/obsolete exported symbols"
+       default y if X86
+       help
+         Unused but exported symbols make the kernel needlessly bigger.  For
+         that reason most of these unused exports will soon be removed.  This
+         option is provided temporarily to provide a transition period in case
+         some external kernel module needs one of these symbols anyway. If you
+         encounter such a case in your module, consider if you are actually
+         using the right API.  (rationale: since nobody in the kernel is using
+         this in a module, there is a pretty good chance it's actually the
+         wrong interface to use).  If you really need the symbol, please send a
+         mail to the linux kernel mailing list mentioning the symbol and why
+         you really need it, and what the merge plan to the mainline kernel for
+         your module is.
+
 config DEBUG_KERNEL
        bool "Kernel debugging"
        help
@@ -107,6 +123,24 @@ config DEBUG_MUTEXES
         This allows mutex semantics violations and mutex related deadlocks
         (lockups) to be detected and reported automatically.
 
+config DEBUG_RT_MUTEXES
+       bool "RT Mutex debugging, deadlock detection"
+       depends on DEBUG_KERNEL && RT_MUTEXES
+       help
+        This allows rt mutex semantics violations and rt mutex related
+        deadlocks (lockups) to be detected and reported automatically.
+
+config DEBUG_PI_LIST
+       bool
+       default y
+       depends on DEBUG_RT_MUTEXES
+
+config RT_MUTEX_TESTER
+       bool "Built-in scriptable tester for rt-mutexes"
+       depends on DEBUG_KERNEL && RT_MUTEXES
+       help
+         This option enables a rt-mutex tester.
+
 config DEBUG_SPINLOCK
        bool "Spinlock debugging"
        depends on DEBUG_KERNEL
index 79358ad1f11353d3ada95577e41a9a857f0f3805..10c13c9d7824d21aa6425001b3a1d0c0403edfa5 100644 (file)
@@ -25,6 +25,7 @@ lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
+obj-$(CONFIG_PLIST) += plist.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 
 ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
diff --git a/lib/plist.c b/lib/plist.c
new file mode 100644 (file)
index 0000000..3074a02
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * lib/plist.c
+ *
+ * Descending-priority-sorted double-linked list
+ *
+ * (C) 2002-2003 Intel Corp
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
+ *
+ * 2001-2005 (c) MontaVista Software, Inc.
+ * Daniel Walker <dwalker@mvista.com>
+ *
+ * (C) 2005 Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Simplifications of the original code by
+ * Oleg Nesterov <oleg@tv-sign.ru>
+ *
+ * Licensed under the FSF's GNU Public License v2 or later.
+ *
+ * Based on simple lists (include/linux/list.h).
+ *
+ * This file contains the add / del functions which are considered to
+ * be too large to inline. See include/linux/plist.h for further
+ * information.
+ */
+
+#include <linux/plist.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_DEBUG_PI_LIST
+
+static void plist_check_prev_next(struct list_head *t, struct list_head *p,
+                                 struct list_head *n)
+{
+       if (n->prev != p || p->next != n) {
+               printk("top: %p, n: %p, p: %p\n", t, t->next, t->prev);
+               printk("prev: %p, n: %p, p: %p\n", p, p->next, p->prev);
+               printk("next: %p, n: %p, p: %p\n", n, n->next, n->prev);
+               WARN_ON(1);
+       }
+}
+
+static void plist_check_list(struct list_head *top)
+{
+       struct list_head *prev = top, *next = top->next;
+
+       plist_check_prev_next(top, prev, next);
+       while (next != top) {
+               prev = next;
+               next = prev->next;
+               plist_check_prev_next(top, prev, next);
+       }
+}
+
+static void plist_check_head(struct plist_head *head)
+{
+       WARN_ON(!head->lock);
+       if (head->lock)
+               WARN_ON_SMP(!spin_is_locked(head->lock));
+       plist_check_list(&head->prio_list);
+       plist_check_list(&head->node_list);
+}
+
+#else
+# define plist_check_head(h)   do { } while (0)
+#endif
+
+/**
+ * plist_add - add @node to @head
+ *
+ * @node:      &struct plist_node pointer
+ * @head:      &struct plist_head pointer
+ */
+void plist_add(struct plist_node *node, struct plist_head *head)
+{
+       struct plist_node *iter;
+
+       plist_check_head(head);
+       WARN_ON(!plist_node_empty(node));
+
+       list_for_each_entry(iter, &head->prio_list, plist.prio_list) {
+               if (node->prio < iter->prio)
+                       goto lt_prio;
+               else if (node->prio == iter->prio) {
+                       iter = list_entry(iter->plist.prio_list.next,
+                                       struct plist_node, plist.prio_list);
+                       goto eq_prio;
+               }
+       }
+
+lt_prio:
+       list_add_tail(&node->plist.prio_list, &iter->plist.prio_list);
+eq_prio:
+       list_add_tail(&node->plist.node_list, &iter->plist.node_list);
+
+       plist_check_head(head);
+}
+
+/**
+ * plist_del - Remove a @node from plist.
+ *
+ * @node:      &struct plist_node pointer - entry to be removed
+ * @head:      &struct plist_head pointer - list head
+ */
+void plist_del(struct plist_node *node, struct plist_head *head)
+{
+       plist_check_head(head);
+
+       if (!list_empty(&node->plist.prio_list)) {
+               struct plist_node *next = plist_first(&node->plist);
+
+               list_move_tail(&next->plist.prio_list, &node->plist.prio_list);
+               list_del_init(&node->plist.prio_list);
+       }
+
+       list_del_init(&node->plist.node_list);
+
+       plist_check_head(head);
+}
index 797428afd1114f3dc1ad3c239917b9f04ceccd55..bed7229378f2da073be0c25eda0a30bf07146380 100644 (file)
@@ -489,7 +489,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                if (str < end)
                        *str = '\0';
                else
-                       *end = '\0';
+                       end[-1] = '\0';
        }
        /* the trailing null byte doesn't count towards the total */
        return str-buf;
index 02a16eacb72dabb50861193db448004b175bd3dc..d84560c076d83cfca8a0d2d19b6214ed1cac23ca 100644 (file)
       bytes, which is the maximum length that can be coded.  inflate_fast()
       requires strm->avail_out >= 258 for each loop to avoid checking for
       output space.
+
+    - @start:  inflate()'s starting value for strm->avail_out
  */
-void inflate_fast(strm, start)
-z_streamp strm;
-unsigned start;         /* inflate()'s starting value for strm->avail_out */
+void inflate_fast(z_streamp strm, unsigned start)
 {
     struct inflate_state *state;
     unsigned char *in;      /* local strm->next_in */
index da665fbb16aaf4e6b9fdf8f69c25b46bc4785f3e..3fe6ce5b53e51999b0ad15f97843b93c313cb60f 100644 (file)
    table index bits.  It will differ if the request is greater than the
    longest code or if it is less than the shortest code.
  */
-int zlib_inflate_table(type, lens, codes, table, bits, work)
-codetype type;
-unsigned short *lens;
-unsigned codes;
-code **table;
-unsigned *bits;
-unsigned short *work;
+int zlib_inflate_table(codetype type, unsigned short *lens, unsigned codes,
+                       code **table, unsigned *bits, unsigned short *work)
 {
     unsigned len;               /* a code's length in bits */
     unsigned sym;               /* index of code symbols */
index 66e65ab3942651e86f2fbbadcf914fd600e41600..8f5b45615f7bf1b43c35253b8f28f1ef4871818e 100644 (file)
@@ -115,7 +115,8 @@ config SPARSEMEM_EXTREME
 # eventually, we can have this option just 'select SPARSEMEM'
 config MEMORY_HOTPLUG
        bool "Allow for memory hot-add"
-       depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND
+       depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG
+       depends on (IA64 || X86 || PPC64)
 
 comment "Memory hotplug is currently incompatible with Software Suspend"
        depends on SPARSEMEM && HOTPLUG && SOFTWARE_SUSPEND
@@ -145,3 +146,9 @@ config MIGRATION
          while the virtual addresses are not changed. This is useful for
          example on NUMA systems to put pages nearer to the processors accessing
          the page.
+
+config RESOURCES_64BIT
+       bool "64 bit Memory and IO resources (EXPERIMENTAL)" if (!64BIT && EXPERIMENTAL)
+       default 64BIT
+       help
+         This option allows memory and IO resources to be 64 bit.
index 9c7334bafda8da5150f4a9f0a7556bda113b8a19..648f2c0c8e18896b1f979f2f31a848986cc6492b 100644 (file)
@@ -2069,7 +2069,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
 {
        struct file *file = iocb->ki_filp;
        struct address_space * mapping = file->f_mapping;
-       struct address_space_operations *a_ops = mapping->a_ops;
+       const struct address_space_operations *a_ops = mapping->a_ops;
        struct inode    *inode = mapping->host;
        long            status = 0;
        struct page     *page;
@@ -2095,14 +2095,21 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
        do {
                unsigned long index;
                unsigned long offset;
-               unsigned long maxlen;
                size_t copied;
 
                offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
                index = pos >> PAGE_CACHE_SHIFT;
                bytes = PAGE_CACHE_SIZE - offset;
-               if (bytes > count)
-                       bytes = count;
+
+               /* Limit the size of the copy to the caller's write size */
+               bytes = min(bytes, count);
+
+               /*
+                * Limit the size of the copy to that of the current segment,
+                * because fault_in_pages_readable() doesn't know how to walk
+                * segments.
+                */
+               bytes = min(bytes, cur_iov->iov_len - iov_base);
 
                /*
                 * Bring in the user page that we will copy from _first_.
@@ -2110,10 +2117,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
                 * same page as we're writing to, without it being marked
                 * up-to-date.
                 */
-               maxlen = cur_iov->iov_len - iov_base;
-               if (maxlen > bytes)
-                       maxlen = bytes;
-               fault_in_pages_readable(buf, maxlen);
+               fault_in_pages_readable(buf, bytes);
 
                page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec);
                if (!page) {
@@ -2121,6 +2125,12 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
                        break;
                }
 
+               if (unlikely(bytes == 0)) {
+                       status = 0;
+                       copied = 0;
+                       goto zero_length_segment;
+               }
+
                status = a_ops->prepare_write(file, page, offset, offset+bytes);
                if (unlikely(status)) {
                        loff_t isize = i_size_read(inode);
@@ -2150,7 +2160,8 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
                        page_cache_release(page);
                        continue;
                }
-               if (likely(copied > 0)) {
+zero_length_segment:
+               if (likely(copied >= 0)) {
                        if (!status)
                                status = copied;
 
@@ -2215,7 +2226,7 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
                                unsigned long nr_segs, loff_t *ppos)
 {
        struct file *file = iocb->ki_filp;
-       struct address_space * mapping = file->f_mapping;
+       const struct address_space * mapping = file->f_mapping;
        size_t ocount;          /* original count */
        size_t count;           /* after file limit checks */
        struct inode    *inode = mapping->host;
index 536979fb4ba717443be39b9e0e8a95dfd012200c..3f2a343c6015f2b4b9564307bb557a0dbdddb8f5 100644 (file)
@@ -88,7 +88,7 @@ filemap_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
        const struct iovec *iov = *iovp;
        size_t base = *basep;
 
-       while (bytes) {
+       do {
                int copy = min(bytes, iov->iov_len - base);
 
                bytes -= copy;
@@ -97,7 +97,7 @@ filemap_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
                        iov++;
                        base = 0;
                }
-       }
+       } while (bytes);
        *iovp = iov;
        *basep = base;
 }
index b960ac8e5918dcb33e64b9b4f822f25540ddb4b4..b4fd0d7c9bfb23e08e2380d9b06bca14de4a95e7 100644 (file)
@@ -273,7 +273,7 @@ __xip_file_write(struct file *filp, const char __user *buf,
                  size_t count, loff_t pos, loff_t *ppos)
 {
        struct address_space * mapping = filp->f_mapping;
-       struct address_space_operations *a_ops = mapping->a_ops;
+       const struct address_space_operations *a_ops = mapping->a_ops;
        struct inode    *inode = mapping->host;
        long            status = 0;
        struct page     *page;
index 841a077d5aeb0d3423ecba8ed5d81efdd72c2442..ea4038838b0a2b4c95a46cc3d4f1eaad25556f5f 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/memory_hotplug.h>
 #include <linux/highmem.h>
 #include <linux/vmalloc.h>
+#include <linux/ioport.h>
 
 #include <asm/tlbflush.h>
 
@@ -126,6 +127,9 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
        unsigned long i;
        unsigned long flags;
        unsigned long onlined_pages = 0;
+       struct resource res;
+       u64 section_end;
+       unsigned long start_pfn;
        struct zone *zone;
        int need_zonelists_rebuild = 0;
 
@@ -148,10 +152,27 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
        if (!populated_zone(zone))
                need_zonelists_rebuild = 1;
 
-       for (i = 0; i < nr_pages; i++) {
-               struct page *page = pfn_to_page(pfn + i);
-               online_page(page);
-               onlined_pages++;
+       res.start = (u64)pfn << PAGE_SHIFT;
+       res.end = res.start + ((u64)nr_pages << PAGE_SHIFT) - 1;
+       res.flags = IORESOURCE_MEM; /* we just need system ram */
+       section_end = res.end;
+
+       while (find_next_system_ram(&res) >= 0) {
+               start_pfn = (unsigned long)(res.start >> PAGE_SHIFT);
+               nr_pages = (unsigned long)
+                           ((res.end + 1 - res.start) >> PAGE_SHIFT);
+
+               if (PageReserved(pfn_to_page(start_pfn))) {
+                       /* this region's page is not onlined now */
+                       for (i = 0; i < nr_pages; i++) {
+                               struct page *page = pfn_to_page(start_pfn + i);
+                               online_page(page);
+                               onlined_pages++;
+                       }
+               }
+
+               res.start = res.end + 1;
+               res.end = section_end;
        }
        zone->present_pages += onlined_pages;
        zone->zone_pgdat->node_present_pages += onlined_pages;
@@ -163,3 +184,100 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
        vm_total_pages = nr_free_pagecache_pages();
        return 0;
 }
+
+static pg_data_t *hotadd_new_pgdat(int nid, u64 start)
+{
+       struct pglist_data *pgdat;
+       unsigned long zones_size[MAX_NR_ZONES] = {0};
+       unsigned long zholes_size[MAX_NR_ZONES] = {0};
+       unsigned long start_pfn = start >> PAGE_SHIFT;
+
+       pgdat = arch_alloc_nodedata(nid);
+       if (!pgdat)
+               return NULL;
+
+       arch_refresh_nodedata(nid, pgdat);
+
+       /* we can use NODE_DATA(nid) from here */
+
+       /* init node's zones as empty zones, we don't have any present pages.*/
+       free_area_init_node(nid, pgdat, zones_size, start_pfn, zholes_size);
+
+       return pgdat;
+}
+
+static void rollback_node_hotadd(int nid, pg_data_t *pgdat)
+{
+       arch_refresh_nodedata(nid, NULL);
+       arch_free_nodedata(pgdat);
+       return;
+}
+
+/* add this memory to iomem resource */
+static void register_memory_resource(u64 start, u64 size)
+{
+       struct resource *res;
+
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       BUG_ON(!res);
+
+       res->name = "System RAM";
+       res->start = start;
+       res->end = start + size - 1;
+       res->flags = IORESOURCE_MEM;
+       if (request_resource(&iomem_resource, res) < 0) {
+               printk("System RAM resource %llx - %llx cannot be added\n",
+               (unsigned long long)res->start, (unsigned long long)res->end);
+               kfree(res);
+       }
+}
+
+
+
+int add_memory(int nid, u64 start, u64 size)
+{
+       pg_data_t *pgdat = NULL;
+       int new_pgdat = 0;
+       int ret;
+
+       if (!node_online(nid)) {
+               pgdat = hotadd_new_pgdat(nid, start);
+               if (!pgdat)
+                       return -ENOMEM;
+               new_pgdat = 1;
+               ret = kswapd_run(nid);
+               if (ret)
+                       goto error;
+       }
+
+       /* call arch's memory hotadd */
+       ret = arch_add_memory(nid, start, size);
+
+       if (ret < 0)
+               goto error;
+
+       /* we online node here. we can't roll back from here. */
+       node_set_online(nid);
+
+       if (new_pgdat) {
+               ret = register_one_node(nid);
+               /*
+                * If sysfs file of new node can't create, cpu on the node
+                * can't be hot-added. There is no rollback way now.
+                * So, check by BUG_ON() to catch it reluctantly..
+                */
+               BUG_ON(ret);
+       }
+
+       /* register this memory as resource */
+       register_memory_resource(start, size);
+
+       return ret;
+error:
+       /* rollback pgdat allocation and others */
+       if (new_pgdat)
+               rollback_node_hotadd(nid, pgdat);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(add_memory);
index 8ccf6f1b1473c1e26e0da73e5f8f95c4b041def9..4ec7026c7bab14e1f4a9e512742e318a6630607f 100644 (file)
@@ -516,14 +516,14 @@ static void set_ratelimit(void)
                ratelimit_pages = (4096 * 1024) / PAGE_CACHE_SIZE;
 }
 
-static int
+static int __cpuinit
 ratelimit_handler(struct notifier_block *self, unsigned long u, void *v)
 {
        set_ratelimit();
        return 0;
 }
 
-static struct notifier_block ratelimit_nb = {
+static struct notifier_block __cpuinitdata ratelimit_nb = {
        .notifier_call  = ratelimit_handler,
        .next           = NULL,
 };
index 9f86191bb632955a224d94ddf6c53980c64e9244..084a2de7e52a8c8b4ceaa3c78997199d17f770e5 100644 (file)
@@ -446,8 +446,8 @@ static void __free_pages_ok(struct page *page, unsigned int order)
 
        arch_free_page(page, order);
        if (!PageHighMem(page))
-               mutex_debug_check_no_locks_freed(page_address(page),
-                                                PAGE_SIZE<<order);
+               debug_check_no_locks_freed(page_address(page),
+                                          PAGE_SIZE<<order);
 
        for (i = 0 ; i < (1 << order) ; ++i)
                reserved += free_pages_check(page + i);
@@ -2009,7 +2009,7 @@ static inline void free_zone_pagesets(int cpu)
        }
 }
 
-static int pageset_cpuup_callback(struct notifier_block *nfb,
+static int __cpuinit pageset_cpuup_callback(struct notifier_block *nfb,
                unsigned long action,
                void *hcpu)
 {
@@ -2031,7 +2031,7 @@ static int pageset_cpuup_callback(struct notifier_block *nfb,
        return ret;
 }
 
-static struct notifier_block pageset_notifier =
+static struct notifier_block __cpuinitdata pageset_notifier =
        { &pageset_cpuup_callback, NULL, 0 };
 
 void __init setup_per_cpu_pageset(void)
index 38bc3334f2633a4bfe9ed0e40361d075ec35d8ec..b14ff817d16264db042313ccb8ba362edc1be014 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
@@ -174,7 +173,7 @@ static inline void shmem_unacct_blocks(unsigned long flags, long pages)
 }
 
 static struct super_operations shmem_ops;
-static struct address_space_operations shmem_aops;
+static const struct address_space_operations shmem_aops;
 static struct file_operations shmem_file_operations;
 static struct inode_operations shmem_inode_operations;
 static struct inode_operations shmem_dir_inode_operations;
@@ -2162,7 +2161,7 @@ static void destroy_inodecache(void)
                printk(KERN_INFO "shmem_inode_cache: not all structures were freed\n");
 }
 
-static struct address_space_operations shmem_aops = {
+static const struct address_space_operations shmem_aops = {
        .writepage      = shmem_writepage,
        .set_page_dirty = __set_page_dirty_nobuffers,
 #ifdef CONFIG_TMPFS
@@ -2252,9 +2251,7 @@ static int __init init_tmpfs(void)
                printk(KERN_ERR "Could not register tmpfs\n");
                goto out2;
        }
-#ifdef CONFIG_TMPFS
-       devfs_mk_dir("shm");
-#endif
+
        shm_mnt = vfs_kern_mount(&tmpfs_fs_type, MS_NOUSER,
                                tmpfs_fs_type.name, NULL);
        if (IS_ERR(shm_mnt)) {
index 98ac20bc0de9a3ad443ef9f8bd54cb1c58ed5de4..233e39d14caf5ae2966c9df788c9c73dc6a563e3 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -89,6 +89,7 @@
 #include       <linux/config.h>
 #include       <linux/slab.h>
 #include       <linux/mm.h>
+#include       <linux/poison.h>
 #include       <linux/swap.h>
 #include       <linux/cache.h>
 #include       <linux/interrupt.h>
 #include       <linux/nodemask.h>
 #include       <linux/mempolicy.h>
 #include       <linux/mutex.h>
+#include       <linux/rtmutex.h>
 
 #include       <asm/uaccess.h>
 #include       <asm/cacheflush.h>
@@ -492,17 +494,6 @@ struct kmem_cache {
 #endif
 
 #if DEBUG
-/*
- * Magic nums for obj red zoning.
- * Placed in the first word before and the first word after an obj.
- */
-#define        RED_INACTIVE    0x5A2CF071UL    /* when obj is inactive */
-#define        RED_ACTIVE      0x170FC2A5UL    /* when obj is active */
-
-/* ...and for poisoning */
-#define        POISON_INUSE    0x5a    /* for use-uninitialised poisoning */
-#define POISON_FREE    0x6b    /* for use-after-free poisoning */
-#define        POISON_END      0xa5    /* end-byte of poisoning */
 
 /*
  * memory layout of objects:
@@ -1083,7 +1074,7 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
 
 #endif
 
-static int cpuup_callback(struct notifier_block *nfb,
+static int __devinit cpuup_callback(struct notifier_block *nfb,
                                    unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
@@ -1265,7 +1256,9 @@ bad:
        return NOTIFY_BAD;
 }
 
-static struct notifier_block cpucache_notifier = { &cpuup_callback, NULL, 0 };
+static struct notifier_block __cpuinitdata cpucache_notifier = {
+       &cpuup_callback, NULL, 0
+};
 
 /*
  * swap the static kmem_list3 with kmalloced memory
@@ -3405,7 +3398,7 @@ void kfree(const void *objp)
        local_irq_save(flags);
        kfree_debugcheck(objp);
        c = virt_to_cache(objp);
-       mutex_debug_check_no_locks_freed(objp, obj_size(c));
+       debug_check_no_locks_freed(objp, obj_size(c));
        __cache_free(c, (void *)objp);
        local_irq_restore(flags);
 }
index e0a3fe48aa3745bebd710ff80d8cad6215dd244d..c7a2b3a0e46b2961fbc6fe6794e562be66def97e 100644 (file)
@@ -45,7 +45,7 @@ static struct mem_section *sparse_index_alloc(int nid)
 
 static int sparse_index_init(unsigned long section_nr, int nid)
 {
-       static spinlock_t index_init_lock = SPIN_LOCK_UNLOCKED;
+       static DEFINE_SPINLOCK(index_init_lock);
        unsigned long root = SECTION_NR_TO_ROOT(section_nr);
        struct mem_section *section;
        int ret = 0;
index e0e1583f32c26cc2579554a4abcc797a9a671553..7535211bb495c9f54a3ece2e37feaa4c0589162d 100644 (file)
@@ -24,7 +24,7 @@
  * vmscan's shrink_list, to make sync_page look nicer, and to allow
  * future use of radix_tree tags in the swap cache.
  */
-static struct address_space_operations swap_aops = {
+static const struct address_space_operations swap_aops = {
        .writepage      = swap_writepage,
        .sync_page      = block_sync_page,
        .set_page_dirty = __set_page_dirty_nobuffers,
index f9d6a9cc91c4bc806700c6119f45e34283abdeb7..5f2cbf0f153c7a35db2219cab124c0ac8513ce4c 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/fs.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/vfs.h>
 #include <linux/mount.h>
 #include <linux/file.h>
@@ -33,9 +32,6 @@ static int __init init_tmpfs(void)
 {
        BUG_ON(register_filesystem(&tmpfs_fs_type) != 0);
 
-#ifdef CONFIG_TMPFS
-       devfs_mk_dir("shm");
-#endif
        shm_mnt = kern_mount(&tmpfs_fs_type);
        BUG_ON(IS_ERR(shm_mnt));
 
index 72babac71deaba28f9c75a1b6d2ccacb8ba537fa..eeacb0d695c35233e57688e4d20314a149d1d22c 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/notifier.h>
 #include <linux/rwsem.h>
 #include <linux/delay.h>
+#include <linux/kthread.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -1223,7 +1224,6 @@ static int kswapd(void *p)
        };
        cpumask_t cpumask;
 
-       daemonize("kswapd%d", pgdat->node_id);
        cpumask = node_to_cpumask(pgdat->node_id);
        if (!cpus_empty(cpumask))
                set_cpus_allowed(tsk, cpumask);
@@ -1450,7 +1450,7 @@ out:
    not required for correctness.  So if the last cpu in a node goes
    away, we get changed to run anywhere: as the first one comes back,
    restore their cpu bindings. */
-static int cpu_callback(struct notifier_block *nfb,
+static int __devinit cpu_callback(struct notifier_block *nfb,
                                  unsigned long action, void *hcpu)
 {
        pg_data_t *pgdat;
@@ -1468,20 +1468,35 @@ static int cpu_callback(struct notifier_block *nfb,
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
+/*
+ * This kswapd start function will be called by init and node-hot-add.
+ * On node-hot-add, kswapd will moved to proper cpus if cpus are hot-added.
+ */
+int kswapd_run(int nid)
+{
+       pg_data_t *pgdat = NODE_DATA(nid);
+       int ret = 0;
+
+       if (pgdat->kswapd)
+               return 0;
+
+       pgdat->kswapd = kthread_run(kswapd, pgdat, "kswapd%d", nid);
+       if (IS_ERR(pgdat->kswapd)) {
+               /* failure at boot is fatal */
+               BUG_ON(system_state == SYSTEM_BOOTING);
+               printk("Failed to start kswapd on node %d\n",nid);
+               ret = -1;
+       }
+       return ret;
+}
+
 static int __init kswapd_init(void)
 {
-       pg_data_t *pgdat;
+       int nid;
 
        swap_setup();
-       for_each_online_pgdat(pgdat) {
-               pid_t pid;
-
-               pid = kernel_thread(kswapd, pgdat, CLONE_KERNEL);
-               BUG_ON(pid < 0);
-               read_lock(&tasklist_lock);
-               pgdat->kswapd = find_task_by_pid(pid);
-               read_unlock(&tasklist_lock);
-       }
+       for_each_online_node(nid)
+               kswapd_run(nid);
        hotcpu_notifier(cpu_callback, 0);
        return 0;
 }
index 74368f79ee5d084e0645c6af221062567f475e47..b105a715fa93e76624b0af98bd9ba1c7126bc7b2 100644 (file)
@@ -480,12 +480,8 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
 
        BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
 
-       if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-               tty_buffer_request_room(tty, skb->len);
-               tty_insert_flip_string(tty, skb->data, skb->len);
-               tty_flip_buffer_push(tty);
-       } else
-               tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
+       tty_insert_flip_string(tty, skb->data, skb->len);
+       tty_flip_buffer_push(tty);
 
        kfree_skb(skb);
 }
@@ -1025,13 +1021,12 @@ int rfcomm_init_ttys(void)
 
        rfcomm_tty_driver->owner        = THIS_MODULE;
        rfcomm_tty_driver->driver_name  = "rfcomm";
-       rfcomm_tty_driver->devfs_name   = "bluetooth/rfcomm/";
        rfcomm_tty_driver->name         = "rfcomm";
        rfcomm_tty_driver->major        = RFCOMM_TTY_MAJOR;
        rfcomm_tty_driver->minor_start  = RFCOMM_TTY_MINOR;
        rfcomm_tty_driver->type         = TTY_DRIVER_TYPE_SERIAL;
        rfcomm_tty_driver->subtype      = SERIAL_TYPE_NORMAL;
-       rfcomm_tty_driver->flags        = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       rfcomm_tty_driver->flags        = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        rfcomm_tty_driver->init_termios = tty_std_termios;
        rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
        tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
index 8a777932786d7d4c0975fd6941489039abad3d06..e728980160d2243400ed49cd2124bd7dfec5bb34 100644 (file)
@@ -349,7 +349,7 @@ static struct rt6_info *rt6_select(struct rt6_info **head, int oif,
            (strict & RT6_SELECT_F_REACHABLE) &&
            last && last != rt0) {
                /* no entries matched; do round-robin */
-               static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+               static DEFINE_SPINLOCK(lock);
                spin_lock(&lock);
                *head = rt0->u.next;
                rt0->u.next = last->u.next;
index 6f20b4206e08a56bc3b79902b9fededeac826cd9..b592c4bc33312a8d7efa7550936ff96182886386 100644 (file)
@@ -124,7 +124,6 @@ static int __init ircomm_tty_init(void)
        driver->owner           = THIS_MODULE;
        driver->driver_name     = "ircomm";
        driver->name            = "ircomm";
-       driver->devfs_name      = "ircomm";
        driver->major           = IRCOMM_TTY_MAJOR;
        driver->minor_start     = IRCOMM_TTY_MINOR;
        driver->type            = TTY_DRIVER_TYPE_SERIAL;
index e4fe1e80029c55cdb89a0b7d5c47763fda282f24..ad6caba02a7be931439ae73f37f56c4b02a992ed 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/tty.h>
 #include <linux/proc_fs.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/netdevice.h>
 #include <linux/miscdevice.h>
 #include <linux/poll.h>
index f43311221a72b9a8b4f56cd177a33e5cd0296b41..2f312164d6d5611559aabab099e37ef8e55f7459 100644 (file)
@@ -70,7 +70,7 @@
 # define RPCDBG_FACILITY        RPCDBG_AUTH
 #endif
 
-spinlock_t krb5_seq_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(krb5_seq_lock);
 
 u32
 gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
index 54128040a1245ad9231ff00db3ebaf12644c273e..1bb75703f3848b8e50bdf57ad561d28f829e8132 100644 (file)
@@ -117,7 +117,7 @@ struct bclink {
 static struct bcbearer *bcbearer = NULL;
 static struct bclink *bclink = NULL;
 static struct link *bcl = NULL;
-static spinlock_t bc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(bc_lock);
 
 char tipc_bclink_name[] = "multicast-link";
 
@@ -796,7 +796,7 @@ int tipc_bclink_init(void)
        memset(bclink, 0, sizeof(struct bclink));
        INIT_LIST_HEAD(&bcl->waiting_ports);
        bcl->next_out_no = 1;
-       bclink->node.lock =  SPIN_LOCK_UNLOCKED;        
+       spin_lock_init(&bclink->node.lock);
        bcl->owner = &bclink->node;
         bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
        tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
index 4fa24b5e8914a559d3cc025731355bb0664e856c..7ef17a449cfdb33d696c19428430ab891c4c316c 100644 (file)
@@ -566,7 +566,7 @@ restart:
                b_ptr->link_req = tipc_disc_init_link_req(b_ptr, &m_ptr->bcast_addr,
                                                          bcast_scope, 2);
        }
-       b_ptr->publ.lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&b_ptr->publ.lock);
        write_unlock_bh(&tipc_net_lock);
        info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
             name, addr_string_fill(addr_string, bcast_scope), priority);
index 3ec502fac8c34b29a0ed66253341e35dfb60a83c..285e1bc2d8808502f53e952eed76a1dd72308534 100644 (file)
@@ -63,7 +63,7 @@ struct manager {
 
 static struct manager mng = { 0};
 
-static spinlock_t config_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(config_lock);
 
 static const void *req_tlv_area;       /* request message TLV area */
 static int req_tlv_space;              /* request message TLV area size */
index 26ef95d5fe38601611e6d95a4d6248276235b4cb..55130655e1edbe306a484f552c2a20080496cb15 100644 (file)
@@ -41,7 +41,7 @@
 #define MAX_STRING 512
 
 static char print_string[MAX_STRING];
-static spinlock_t print_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(print_lock);
 
 static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
 struct print_buf *TIPC_CONS = &cons_buf;
index 966f70a1b60800012c14a09e7377eeea2414c0d0..ae6ddf00a1aaea8aaaa17d708e4d4eaca4bfe059 100644 (file)
@@ -44,7 +44,7 @@ struct queue_item {
 
 static kmem_cache_t *tipc_queue_item_cache;
 static struct list_head signal_queue_head;
-static spinlock_t qitem_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(qitem_lock);
 static int handler_enabled = 0;
 
 static void process_signal_queue(unsigned long dummy);
index 38571306aba5ab0bb60a86be10a0c8202b28f40a..a6926ff07bcc3e2365d0424e30b721df1e455d21 100644 (file)
@@ -101,7 +101,7 @@ struct name_table {
 
 static struct name_table table = { NULL } ;
 static atomic_t rsv_publ_ok = ATOMIC_INIT(0);
-rwlock_t tipc_nametbl_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(tipc_nametbl_lock);
 
 
 static int hash(int x)
@@ -172,7 +172,7 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea
        }
 
        memset(nseq, 0, sizeof(*nseq));
-       nseq->lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&nseq->lock);
        nseq->type = type;
        nseq->sseqs = sseq;
        dbg("tipc_nameseq_create(): nseq = %p, type %u, ssseqs %p, ff: %u\n",
index f7c8223ddf7dd0f3e9ce9c148e2cca1d1915cb3f..e5a359ab49308025f10a1c065cfffa23e7991a5f 100644 (file)
  *     - A local spin_lock protecting the queue of subscriber events.
 */
 
-rwlock_t tipc_net_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(tipc_net_lock);
 struct network tipc_net = { NULL };
 
 struct node *tipc_net_select_remote_node(u32 addr, u32 ref) 
index ce9678efa98a5822b5e205d879fb158b3f8ddb44..861322b935daf1be3aee4ac4e5eca284c4a7c89a 100644 (file)
@@ -77,7 +77,7 @@ struct node *tipc_node_create(u32 addr)
                
        memset(n_ptr, 0, sizeof(*n_ptr));
        n_ptr->addr = addr;
-       n_ptr->lock =  SPIN_LOCK_UNLOCKED;      
+                spin_lock_init(&n_ptr->lock);
        INIT_LIST_HEAD(&n_ptr->nsub);
        n_ptr->owner = c_ptr;
        tipc_cltr_attach_node(c_ptr, n_ptr);
index 47d97404e3ee06a3de6d9f2721af8211a78fd8d3..3251c8d8e53c3bcc401a13e53d6636d410b6b5d0 100644 (file)
@@ -57,8 +57,8 @@
 static struct sk_buff *msg_queue_head = NULL;
 static struct sk_buff *msg_queue_tail = NULL;
 
-spinlock_t tipc_port_list_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(tipc_port_list_lock);
+static DEFINE_SPINLOCK(queue_lock);
 
 static LIST_HEAD(ports);
 static void port_handle_node_down(unsigned long ref);
index d2f0cce10e2046c0e9693b113c6e234b30792f1a..596d3c8ff75006a95545e9f1a9407bd5e6b9d062 100644 (file)
@@ -63,7 +63,7 @@
 
 struct ref_table tipc_ref_table = { NULL };
 
-static rwlock_t ref_table_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(ref_table_lock);
 
 /**
  * tipc_ref_table_init - create reference table for objects
@@ -87,7 +87,7 @@ int tipc_ref_table_init(u32 requested_size, u32 start)
        index_mask = sz - 1;
        for (i = sz - 1; i >= 0; i--) {
                table[i].object = NULL;
-               table[i].lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&table[i].lock);
                table[i].data.next_plus_upper = (start & ~index_mask) + i - 1;
        }
        tipc_ref_table.entries = table;
index fc171875660c5eda665c7674509ab9dc72fac057..e19b4bcd67ec2bf44b6a2e7f4186751984782c4b 100644 (file)
@@ -457,7 +457,7 @@ int tipc_subscr_start(void)
        int res = -1;
 
        memset(&topsrv, 0, sizeof (topsrv));
-       topsrv.lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&topsrv.lock);
        INIT_LIST_HEAD(&topsrv.subscriber_list);
 
        spin_lock_bh(&topsrv.lock);
index 3f3f933976e9dc27603cff2deec0b74150faebc4..1e3ae57c722872f2e2d74d28891ecb39d53d0f21 100644 (file)
@@ -67,7 +67,7 @@ struct tipc_user {
 
 static struct tipc_user *users = NULL;
 static u32 next_free_user = MAX_USERID + 1;
-static spinlock_t reg_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(reg_lock);
 
 /**
  * reg_init - create TIPC user registry (but don't activate it)
index ac5f275b0283f1f9807fcc281c3a443e30955eda..b0d067be739056089fbb09a357bbacc5c0daf6b4 100644 (file)
@@ -12,11 +12,6 @@ space   := $(empty) $(empty)
 # contain a comma
 depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
 
-###
-# basetarget equals the filename of the target with no extension.
-# So 'foo/bar.o' becomes 'bar'
-basetarget = $(basename $(notdir $@))
-
 ###
 # Escape single quote for use in echo statements
 escsq = $(subst $(squote),'\$(squote)',$1)
index 3cb445cc7432fdac293fcea287a62e437fee921f..02a7eea5fdbcb77221eca244d264d33c1eada5f5 100644 (file)
@@ -117,7 +117,7 @@ $(real-objs-m:.o=.lst): quiet_modtag := [M]
 $(obj-m)              : quiet_modtag := [M]
 
 # Default for not multi-part modules
-modname = $(basetarget)
+modname = $(*F)
 
 $(multi-objs-m)         : modname = $(modname-multi)
 $(multi-objs-m:.o=.i)   : modname = $(modname-multi)
index 18ecd4d5df7fe4ae76352cc926605cc304040958..2b066d12af2c30fe65c51a0b204cdfb6ac494f2b 100644 (file)
@@ -80,10 +80,8 @@ obj-dirs += $(host-objdirs)
 #####
 # Handle options to gcc. Support building with separate output directory
 
-_hostc_flags   = $(HOSTCFLAGS)   $(HOST_EXTRACFLAGS)   \
-                 $(HOSTCFLAGS_$(basetarget).o)
-_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \
-                 $(HOSTCXXFLAGS_$(basetarget).o)
+_hostc_flags   = $(HOSTCFLAGS)   $(HOST_EXTRACFLAGS)   $(HOSTCFLAGS_$(*F).o)
+_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) $(HOSTCXXFLAGS_$(*F).o)
 
 ifeq ($(KBUILD_SRC),)
 __hostc_flags  = $(_hostc_flags)
index fc498fee68edefe6c88afc2d546e0e459b9396d9..2cb4935e85d1b0a8d3638783a8bd964489f984c1 100644 (file)
@@ -82,12 +82,12 @@ obj-dirs    := $(addprefix $(obj)/,$(obj-dirs))
 #       than one module. In that case KBUILD_MODNAME will be set to foo_bar,
 #       where foo and bar are the name of the modules.
 name-fix = $(subst $(comma),_,$(subst -,_,$1))
-basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(*F)))"
 modname_flags  = $(if $(filter 1,$(words $(modname))),\
                  -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
 
-_c_flags       = $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$(basetarget).o)
-_a_flags       = $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$(basetarget).o)
+_c_flags       = $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$(*F).o)
+_a_flags       = $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
 _cpp_flags     = $(CPPFLAGS) $(EXTRA_CPPFLAGS) $(CPPFLAGS_$(@F))
 
 # If building the kernel in a separate objtree expand all occurrences
index e83613e0e82726b66541f0c28ace5232d07b365a..576cce5e387f4472bc31a20fcfca2e08fcea6fdd 100644 (file)
@@ -72,7 +72,7 @@ $(modules:.ko=.mod.c): __modpost ;
 # Step 5), compile all *.mod.c files
 
 # modname is set to make c_flags define KBUILD_MODNAME
-modname = $(basetarget)
+modname = $(*F)
 
 quiet_cmd_cc_o_c = CC      $@
       cmd_cc_o_c = $(CC) $(c_flags) $(CFLAGS_MODULE)   \
diff --git a/scripts/rt-tester/check-all.sh b/scripts/rt-tester/check-all.sh
new file mode 100644 (file)
index 0000000..43098af
--- /dev/null
@@ -0,0 +1,22 @@
+
+
+function testit ()
+{
+ printf "%-30s: " $1
+ ./rt-tester.py $1 | grep Pass
+}
+
+testit t2-l1-2rt-sameprio.tst
+testit t2-l1-pi.tst
+testit t2-l1-signal.tst
+#testit t2-l2-2rt-deadlock.tst
+testit t3-l1-pi-1rt.tst
+testit t3-l1-pi-2rt.tst
+testit t3-l1-pi-3rt.tst
+testit t3-l1-pi-signal.tst
+testit t3-l1-pi-steal.tst
+testit t3-l2-pi.tst
+testit t4-l2-pi-deboost.tst
+testit t5-l4-pi-boost-deboost.tst
+testit t5-l4-pi-boost-deboost-setsched.tst
+
diff --git a/scripts/rt-tester/rt-tester.py b/scripts/rt-tester/rt-tester.py
new file mode 100644 (file)
index 0000000..4c79660
--- /dev/null
@@ -0,0 +1,222 @@
+#!/usr/bin/env python
+#
+# rt-mutex tester
+#
+# (C) 2006 Thomas Gleixner <tglx@linutronix.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+import os
+import sys
+import getopt
+import shutil
+import string
+
+# Globals
+quiet = 0
+test = 0
+comments = 0
+
+sysfsprefix = "/sys/devices/system/rttest/rttest"
+statusfile = "/status"
+commandfile = "/command"
+
+# Command opcodes
+cmd_opcodes = {
+    "schedother"    : "1",
+    "schedfifo"     : "2",
+    "lock"          : "3",
+    "locknowait"    : "4",
+    "lockint"       : "5",
+    "lockintnowait" : "6",
+    "lockcont"      : "7",
+    "unlock"        : "8",
+    "lockbkl"       : "9",
+    "unlockbkl"     : "10",
+    "signal"        : "11",
+    "resetevent"    : "98",
+    "reset"         : "99",
+    }
+
+test_opcodes = {
+    "prioeq"        : ["P" , "eq" , None],
+    "priolt"        : ["P" , "lt" , None],
+    "priogt"        : ["P" , "gt" , None],
+    "nprioeq"       : ["N" , "eq" , None],
+    "npriolt"       : ["N" , "lt" , None],
+    "npriogt"       : ["N" , "gt" , None],
+    "unlocked"      : ["M" , "eq" , 0],
+    "trylock"       : ["M" , "eq" , 1],
+    "blocked"       : ["M" , "eq" , 2],
+    "blockedwake"   : ["M" , "eq" , 3],
+    "locked"        : ["M" , "eq" , 4],
+    "opcodeeq"      : ["O" , "eq" , None],
+    "opcodelt"      : ["O" , "lt" , None],
+    "opcodegt"      : ["O" , "gt" , None],
+    "eventeq"       : ["E" , "eq" , None],
+    "eventlt"       : ["E" , "lt" , None],
+    "eventgt"       : ["E" , "gt" , None],
+    }
+
+# Print usage information
+def usage():
+    print "rt-tester.py <-c -h -q -t> <testfile>"
+    print " -c    display comments after first command"
+    print " -h    help"
+    print " -q    quiet mode"
+    print " -t    test mode (syntax check)"
+    print " testfile: read test specification from testfile"
+    print " otherwise from stdin"
+    return
+
+# Print progress when not in quiet mode
+def progress(str):
+    if not quiet:
+        print str
+
+# Analyse a status value
+def analyse(val, top, arg):
+
+    intval = int(val)
+
+    if top[0] == "M":
+        intval = intval / (10 ** int(arg))
+       intval = intval % 10
+        argval = top[2]
+    elif top[0] == "O":
+        argval = int(cmd_opcodes.get(arg, arg))
+    else:
+        argval = int(arg)
+
+    # progress("%d %s %d" %(intval, top[1], argval))
+
+    if top[1] == "eq" and intval == argval:
+       return 1
+    if top[1] == "lt" and intval < argval:
+        return 1
+    if top[1] == "gt" and intval > argval:
+       return 1
+    return 0
+
+# Parse the commandline
+try:
+    (options, arguments) = getopt.getopt(sys.argv[1:],'chqt')
+except getopt.GetoptError, ex:
+    usage()
+    sys.exit(1)
+
+# Parse commandline options
+for option, value in options:
+    if option == "-c":
+        comments = 1
+    elif option == "-q":
+        quiet = 1
+    elif option == "-t":
+        test = 1
+    elif option == '-h':
+        usage()
+        sys.exit(0)
+
+# Select the input source
+if arguments:
+    try:
+        fd = open(arguments[0])
+    except Exception,ex:
+        sys.stderr.write("File not found %s\n" %(arguments[0]))
+        sys.exit(1)
+else:
+    fd = sys.stdin
+
+linenr = 0
+
+# Read the test patterns
+while 1:
+
+    linenr = linenr + 1
+    line = fd.readline()
+    if not len(line):
+        break
+
+    line = line.strip()
+    parts = line.split(":")
+
+    if not parts or len(parts) < 1:
+        continue
+
+    if len(parts[0]) == 0:
+        continue
+
+    if parts[0].startswith("#"):
+       if comments > 1:
+           progress(line)
+       continue
+
+    if comments == 1:
+       comments = 2
+
+    progress(line)
+
+    cmd = parts[0].strip().lower()
+    opc = parts[1].strip().lower()
+    tid = parts[2].strip()
+    dat = parts[3].strip()
+
+    try:
+        # Test or wait for a status value
+        if cmd == "t" or cmd == "w":
+            testop = test_opcodes[opc]
+
+            fname = "%s%s%s" %(sysfsprefix, tid, statusfile)
+            if test:
+               print fname
+                continue
+
+            while 1:
+                query = 1
+                fsta = open(fname, 'r')
+                status = fsta.readline().strip()
+                fsta.close()
+                stat = status.split(",")
+                for s in stat:
+                   s = s.strip()
+                    if s.startswith(testop[0]):
+                        # Seperate status value
+                        val = s[2:].strip()
+                        query = analyse(val, testop, dat)
+                        break
+                if query or cmd == "t":
+                    break
+
+            progress("   " + status)
+
+            if not query:
+                sys.stderr.write("Test failed in line %d\n" %(linenr))
+               sys.exit(1)
+
+        # Issue a command to the tester
+        elif cmd == "c":
+            cmdnr = cmd_opcodes[opc]
+            # Build command string and sys filename
+            cmdstr = "%s:%s" %(cmdnr, dat)
+            fname = "%s%s%s" %(sysfsprefix, tid, commandfile)
+            if test:
+               print fname
+                continue
+            fcmd = open(fname, 'w')
+            fcmd.write(cmdstr)
+            fcmd.close()
+
+    except Exception,ex:
+       sys.stderr.write(str(ex))
+        sys.stderr.write("\nSyntax error in line %d\n" %(linenr))
+        if not test:
+            fd.close()
+            sys.exit(1)
+
+# Normal exit pass
+print "Pass"
+sys.exit(0)
+
+
diff --git a/scripts/rt-tester/t2-l1-2rt-sameprio.tst b/scripts/rt-tester/t2-l1-2rt-sameprio.tst
new file mode 100644 (file)
index 0000000..8821f27
--- /dev/null
@@ -0,0 +1,99 @@
+#
+# RT-Mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       0
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 2 threads 1 lock
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedfifo:          0:      80
+C: schedfifo:          1:      80
+
+# T0 lock L0
+C: locknowait:         0:      0
+C: locknowait:         1:      0
+W: locked:             0:      0
+W: blocked:            1:      0
+T: prioeq:             0:      80
+
+# T0 unlock L0
+C: unlock:             0:      0
+W: locked:             1:      0
+
+# Verify T0
+W: unlocked:           0:      0
+T: prioeq:             0:      80
+
+# Unlock
+C: unlock:             1:      0
+W: unlocked:           1:      0
+
+# T1,T0 lock L0
+C: locknowait:         1:      0
+C: locknowait:         0:      0
+W: locked:             1:      0
+W: blocked:            0:      0
+T: prioeq:             1:      80
+
+# T1 unlock L0
+C: unlock:             1:      0
+W: locked:             0:      0
+
+# Verify T1
+W: unlocked:           1:      0
+T: prioeq:             1:      80
+
+# Unlock and exit
+C: unlock:             0:      0
+W: unlocked:           0:      0
+
diff --git a/scripts/rt-tester/t2-l1-pi.tst b/scripts/rt-tester/t2-l1-pi.tst
new file mode 100644 (file)
index 0000000..cde1f18
--- /dev/null
@@ -0,0 +1,82 @@
+#
+# RT-Mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       0
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 2 threads 1 lock with priority inversion
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedfifo:          1:      80
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      80
+
+# T0 unlock L0
+C: unlock:             0:      0
+W: locked:             1:      0
+
+# Verify T1
+W: unlocked:           0:      0
+T: priolt:             0:      1
+
+# Unlock and exit
+C: unlock:             1:      0
+W: unlocked:           1:      0
+
diff --git a/scripts/rt-tester/t2-l1-signal.tst b/scripts/rt-tester/t2-l1-signal.tst
new file mode 100644 (file)
index 0000000..3ab0bfc
--- /dev/null
@@ -0,0 +1,77 @@
+#
+# RT-Mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       0
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 2 threads 1 lock with priority inversion
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedother:         1:      0
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: lockintnowait:      1:      0
+W: blocked:            1:      0
+
+# Interrupt T1
+C: signal:             1:      0
+W: unlocked:           1:      0
+T: opcodeeq:           1:      -4
+
+# Unlock and exit
+C: unlock:             0:      0
+W: unlocked:           0:      0
diff --git a/scripts/rt-tester/t2-l2-2rt-deadlock.tst b/scripts/rt-tester/t2-l2-2rt-deadlock.tst
new file mode 100644 (file)
index 0000000..f4b5d5d
--- /dev/null
@@ -0,0 +1,89 @@
+#
+# RT-Mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       0
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 2 threads 2 lock
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedfifo:          0:      80
+C: schedfifo:          1:      80
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L1
+C: locknowait:         1:      1
+W: locked:             1:      1
+
+# T0 lock L1
+C: lockintnowait:      0:      1
+W: blocked:            0:      1
+
+# T1 lock L0
+C: lockintnowait:      1:      0
+W: blocked:            1:      0
+
+# Make deadlock go away
+C: signal:             1:      0
+W: unlocked:           1:      0
+C: signal:             0:      0
+W: unlocked:           0:      1
+
+# Unlock and exit
+C: unlock:             0:      0
+W: unlocked:           0:      0
+C: unlock:             1:      1
+W: unlocked:           1:      1
+
diff --git a/scripts/rt-tester/t3-l1-pi-1rt.tst b/scripts/rt-tester/t3-l1-pi-1rt.tst
new file mode 100644 (file)
index 0000000..63440ca
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 3 threads 1 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedother:         1:      0
+C: schedfifo:          2:      82
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: priolt:             0:      1
+
+# T2 lock L0
+C: locknowait:         2:      0
+W: blocked:            2:      0
+T: prioeq:             0:      82
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T2 got the lock
+W: locked:             2:      0
+W: unlocked:           0:      0
+T: priolt:             0:      1
+
+# T2 unlock L0
+C: unlock:             2:      0
+
+W: unlocked:           2:      0
+W: locked:             1:      0
+
+C: unlock:             1:      0
+W: unlocked:           1:      0
diff --git a/scripts/rt-tester/t3-l1-pi-2rt.tst b/scripts/rt-tester/t3-l1-pi-2rt.tst
new file mode 100644 (file)
index 0000000..e5816fe
--- /dev/null
@@ -0,0 +1,93 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 3 threads 1 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedfifo:          1:      81
+C: schedfifo:          2:      82
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      81
+
+# T2 lock L0
+C: locknowait:         2:      0
+W: blocked:            2:      0
+T: prioeq:             0:      82
+T: prioeq:             1:      81
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T2 got the lock
+W: locked:             2:      0
+W: unlocked:           0:      0
+T: priolt:             0:      1
+
+# T2 unlock L0
+C: unlock:             2:      0
+
+W: unlocked:           2:      0
+W: locked:             1:      0
+
+C: unlock:             1:      0
+W: unlocked:           1:      0
diff --git a/scripts/rt-tester/t3-l1-pi-3rt.tst b/scripts/rt-tester/t3-l1-pi-3rt.tst
new file mode 100644 (file)
index 0000000..718b82b
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 3 threads 1 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedfifo:          0:      80
+C: schedfifo:          1:      81
+C: schedfifo:          2:      82
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      81
+
+# T2 lock L0
+C: locknowait:         2:      0
+W: blocked:            2:      0
+T: prioeq:             0:      82
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T2 got the lock
+W: locked:             2:      0
+W: unlocked:           0:      0
+T: prioeq:             0:      80
+
+# T2 unlock L0
+C: unlock:             2:      0
+
+W: locked:             1:      0
+W: unlocked:           2:      0
+
+C: unlock:             1:      0
+W: unlocked:           1:      0
diff --git a/scripts/rt-tester/t3-l1-pi-signal.tst b/scripts/rt-tester/t3-l1-pi-signal.tst
new file mode 100644 (file)
index 0000000..c6e2135
--- /dev/null
@@ -0,0 +1,98 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+# Reset event counter
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set priorities
+C: schedother:         0:      0
+C: schedfifo:          1:      80
+C: schedfifo:          2:      81
+
+# T0 lock L0
+C: lock:               0:      0
+W: locked:             0:      0
+
+# T1 lock L0, no wait in the wakeup path
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      80
+T: prioeq:             1:      80
+
+# T2 lock L0 interruptible, no wait in the wakeup path
+C: lockintnowait:      2:      0
+W: blocked:            2:      0
+T: prioeq:             0:      81
+T: prioeq:             1:      80
+
+# Interrupt T2
+C: signal:             2:      2
+W: unlocked:           2:      0
+T: prioeq:             1:      80
+T: prioeq:             0:      80
+
+T: locked:             0:      0
+T: blocked:            1:      0
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T1 has locked L0 and exit
+W: locked:             1:      0
+W: unlocked:           0:      0
+T: priolt:             0:      1
+
+C: unlock:             1:      0
+W: unlocked:           1:      0
+
+
+
diff --git a/scripts/rt-tester/t3-l1-pi-steal.tst b/scripts/rt-tester/t3-l1-pi-steal.tst
new file mode 100644 (file)
index 0000000..f53749d
--- /dev/null
@@ -0,0 +1,96 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 3 threads 1 lock PI steal pending ownership
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedfifo:          1:      80
+C: schedfifo:          2:      81
+
+# T0 lock L0
+C: lock:               0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: lock:               1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      80
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T1 is in the wakeup loop
+W: blockedwake:                1:      0
+T: priolt:             0:      1
+
+# T2 lock L0
+C: lock:               2:      0
+# T1 leave wakeup loop
+C: lockcont:           1:      0
+
+# T2 must have the lock and T1 must be blocked
+W: locked:             2:      0
+W: blocked:            1:      0
+
+# T2 unlock L0
+C: unlock:             2:      0
+
+# Wait until T1 is in the wakeup loop and let it run
+W: blockedwake:                1:      0
+C: lockcont:           1:      0
+W: locked:             1:      0
+C: unlock:             1:      0
+W: unlocked:           1:      0
diff --git a/scripts/rt-tester/t3-l2-pi.tst b/scripts/rt-tester/t3-l2-pi.tst
new file mode 100644 (file)
index 0000000..cdc3e4f
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 3 threads 2 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedother:         1:      0
+C: schedfifo:          2:      82
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L0
+C: locknowait:         1:      0
+W: blocked:            1:      0
+T: priolt:             0:      1
+
+# T2 lock L0
+C: locknowait:         2:      0
+W: blocked:            2:      0
+T: prioeq:             0:      82
+
+# T0 unlock L0
+C: unlock:             0:      0
+
+# Wait until T2 got the lock
+W: locked:             2:      0
+W: unlocked:           0:      0
+T: priolt:             0:      1
+
+# T2 unlock L0
+C: unlock:             2:      0
+
+W: unlocked:           2:      0
+W: locked:             1:      0
+
+C: unlock:             1:      0
+W: unlocked:           1:      0
diff --git a/scripts/rt-tester/t4-l2-pi-deboost.tst b/scripts/rt-tester/t4-l2-pi-deboost.tst
new file mode 100644 (file)
index 0000000..baa1413
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 4 threads 2 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedother:         1:      0
+C: schedfifo:          2:      82
+C: schedfifo:          3:      83
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L1
+C: locknowait:         1:      1
+W: locked:             1:      1
+
+# T3 lock L0
+C: lockintnowait:      3:      0
+W: blocked:            3:      0
+T: prioeq:             0:      83
+
+# T0 lock L1
+C: lock:               0:      1
+W: blocked:            0:      1
+T: prioeq:             1:      83
+
+# T1 unlock L1
+C: unlock:             1:      1
+
+# Wait until T0 is in the wakeup code
+W: blockedwake:                0:      1
+
+# Verify that T1 is unboosted
+W: unlocked:           1:      1
+T: priolt:             1:      1
+
+# T2 lock L1 (T0 is boosted and pending owner !)
+C: locknowait:         2:      1
+W: blocked:            2:      1
+T: prioeq:             0:      83
+
+# Interrupt T3 and wait until T3 returned
+C: signal:             3:      0
+W: unlocked:           3:      0
+
+# Verify prio of T0 (still pending owner,
+# but T2 is enqueued due to the previous boost by T3
+T: prioeq:             0:      82
+
+# Let T0 continue
+C: lockcont:           0:      1
+W: locked:             0:      1
+
+# Unlock L1 and let T2 get L1
+C: unlock:             0:      1
+W: locked:             2:      1
+
+# Verify that T0 is unboosted
+W: unlocked:           0:      1
+T: priolt:             0:      1
+
+# Unlock everything and exit
+C: unlock:             2:      1
+W: unlocked:           2:      1
+
+C: unlock:             0:      0
+W: unlocked:           0:      0
+
diff --git a/scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst b/scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst
new file mode 100644 (file)
index 0000000..e6ec0c8
--- /dev/null
@@ -0,0 +1,183 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 5 threads 4 lock PI - modify priority of blocked threads
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedfifo:          1:      81
+C: schedfifo:          2:      82
+C: schedfifo:          3:      83
+C: schedfifo:          4:      84
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L1
+C: locknowait:         1:      1
+W: locked:             1:      1
+
+# T1 lock L0
+C: lockintnowait:      1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      81
+
+# T2 lock L2
+C: locknowait:         2:      2
+W: locked:             2:      2
+
+# T2 lock L1
+C: lockintnowait:      2:      1
+W: blocked:            2:      1
+T: prioeq:             0:      82
+T: prioeq:             1:      82
+
+# T3 lock L3
+C: locknowait:         3:      3
+W: locked:             3:      3
+
+# T3 lock L2
+C: lockintnowait:      3:      2
+W: blocked:            3:      2
+T: prioeq:             0:      83
+T: prioeq:             1:      83
+T: prioeq:             2:      83
+
+# T4 lock L3
+C: lockintnowait:      4:      3
+W: blocked:            4:      3
+T: prioeq:             0:      84
+T: prioeq:             1:      84
+T: prioeq:             2:      84
+T: prioeq:             3:      84
+
+# Reduce prio of T4
+C: schedfifo:          4:      80
+T: prioeq:             0:      83
+T: prioeq:             1:      83
+T: prioeq:             2:      83
+T: prioeq:             3:      83
+T: prioeq:             4:      80
+
+# Increase prio of T4
+C: schedfifo:          4:      84
+T: prioeq:             0:      84
+T: prioeq:             1:      84
+T: prioeq:             2:      84
+T: prioeq:             3:      84
+T: prioeq:             4:      84
+
+# Reduce prio of T3
+C: schedfifo:          3:      80
+T: prioeq:             0:      84
+T: prioeq:             1:      84
+T: prioeq:             2:      84
+T: prioeq:             3:      84
+T: prioeq:             4:      84
+
+# Increase prio of T3
+C: schedfifo:          3:      85
+T: prioeq:             0:      85
+T: prioeq:             1:      85
+T: prioeq:             2:      85
+T: prioeq:             3:      85
+T: prioeq:             4:      84
+
+# Reduce prio of T3
+C: schedfifo:          3:      83
+T: prioeq:             0:      84
+T: prioeq:             1:      84
+T: prioeq:             2:      84
+T: prioeq:             3:      84
+T: prioeq:             4:      84
+
+# Signal T4
+C: signal:             4:      0
+W: unlocked:           4:      3
+T: prioeq:             0:      83
+T: prioeq:             1:      83
+T: prioeq:             2:      83
+T: prioeq:             3:      83
+
+# Signal T3
+C: signal:             3:      0
+W: unlocked:           3:      2
+T: prioeq:             0:      82
+T: prioeq:             1:      82
+T: prioeq:             2:      82
+
+# Signal T2
+C: signal:             2:      0
+W: unlocked:           2:      1
+T: prioeq:             0:      81
+T: prioeq:             1:      81
+
+# Signal T1
+C: signal:             1:      0
+W: unlocked:           1:      0
+T: priolt:             0:      1
+
+# Unlock and exit
+C: unlock:             3:      3
+C: unlock:             2:      2
+C: unlock:             1:      1
+C: unlock:             0:      0
+
+W: unlocked:           3:      3
+W: unlocked:           2:      2
+W: unlocked:           1:      1
+W: unlocked:           0:      0
+
diff --git a/scripts/rt-tester/t5-l4-pi-boost-deboost.tst b/scripts/rt-tester/t5-l4-pi-boost-deboost.tst
new file mode 100644 (file)
index 0000000..ca64f8b
--- /dev/null
@@ -0,0 +1,143 @@
+#
+# rt-mutex test
+#
+# Op: C(ommand)/T(est)/W(ait)
+# |  opcode
+# |  |     threadid: 0-7
+# |  |     |  opcode argument
+# |  |     |  |
+# C: lock: 0: 0
+#
+# Commands
+#
+# opcode       opcode argument
+# schedother   nice value
+# schedfifo    priority
+# lock         lock nr (0-7)
+# locknowait   lock nr (0-7)
+# lockint      lock nr (0-7)
+# lockintnowait        lock nr (0-7)
+# lockcont     lock nr (0-7)
+# unlock       lock nr (0-7)
+# lockbkl      lock nr (0-7)
+# unlockbkl    lock nr (0-7)
+# signal       thread to signal (0-7)
+# reset                0
+# resetevent   0
+#
+# Tests / Wait
+#
+# opcode       opcode argument
+#
+# prioeq       priority
+# priolt       priority
+# priogt       priority
+# nprioeq      normal priority
+# npriolt      normal priority
+# npriogt      normal priority
+# locked       lock nr (0-7)
+# blocked      lock nr (0-7)
+# blockedwake  lock nr (0-7)
+# unlocked     lock nr (0-7)
+# lockedbkl    dont care
+# blockedbkl   dont care
+# unlockedbkl  dont care
+# opcodeeq     command opcode or number
+# opcodelt     number
+# opcodegt     number
+# eventeq      number
+# eventgt      number
+# eventlt      number
+
+#
+# 5 threads 4 lock PI
+#
+C: resetevent:         0:      0
+W: opcodeeq:           0:      0
+
+# Set schedulers
+C: schedother:         0:      0
+C: schedfifo:          1:      81
+C: schedfifo:          2:      82
+C: schedfifo:          3:      83
+C: schedfifo:          4:      84
+
+# T0 lock L0
+C: locknowait:         0:      0
+W: locked:             0:      0
+
+# T1 lock L1
+C: locknowait:         1:      1
+W: locked:             1:      1
+
+# T1 lock L0
+C: lockintnowait:      1:      0
+W: blocked:            1:      0
+T: prioeq:             0:      81
+
+# T2 lock L2
+C: locknowait:         2:      2
+W: locked:             2:      2
+
+# T2 lock L1
+C: lockintnowait:      2:      1
+W: blocked:            2:      1
+T: prioeq:             0:      82
+T: prioeq:             1:      82
+
+# T3 lock L3
+C: locknowait:         3:      3
+W: locked:             3:      3
+
+# T3 lock L2
+C: lockintnowait:      3:      2
+W: blocked:            3:      2
+T: prioeq:             0:      83
+T: prioeq:             1:      83
+T: prioeq:             2:      83
+
+# T4 lock L3
+C: lockintnowait:      4:      3
+W: blocked:            4:      3
+T: prioeq:             0:      84
+T: prioeq:             1:      84
+T: prioeq:             2:      84
+T: prioeq:             3:      84
+
+# Signal T4
+C: signal:             4:      0
+W: unlocked:           4:      3
+T: prioeq:             0:      83
+T: prioeq:             1:      83
+T: prioeq:             2:      83
+T: prioeq:             3:      83
+
+# Signal T3
+C: signal:             3:      0
+W: unlocked:           3:      2
+T: prioeq:             0:      82
+T: prioeq:             1:      82
+T: prioeq:             2:      82
+
+# Signal T2
+C: signal:             2:      0
+W: unlocked:           2:      1
+T: prioeq:             0:      81
+T: prioeq:             1:      81
+
+# Signal T1
+C: signal:             1:      0
+W: unlocked:           1:      0
+T: priolt:             0:      1
+
+# Unlock and exit
+C: unlock:             3:      3
+C: unlock:             2:      2
+C: unlock:             1:      1
+C: unlock:             0:      0
+
+W: unlocked:           3:      3
+W: unlocked:           2:      2
+W: unlocked:           1:      1
+W: unlocked:           0:      0
+
index 3c2877f0663ebc6f60d5a9585ff985df52a502f5..1bb416f4bbcef7aa9315e9efcb59d292389ee8b2 100644 (file)
@@ -99,6 +99,7 @@ extern int install_process_keyring(struct task_struct *tsk);
 extern struct key *request_key_and_link(struct key_type *type,
                                        const char *description,
                                        const char *callout_info,
+                                       void *aux,
                                        struct key *dest_keyring,
                                        unsigned long flags);
 
index 43295ca37b5dcb7b3461dc16645513a6df84ecf8..80de8c3e9cc3ea49c79e6525b0ce17b22076ac3e 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/poison.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/security.h>
@@ -988,7 +989,7 @@ void unregister_key_type(struct key_type *ktype)
                if (key->type == ktype) {
                        if (ktype->destroy)
                                ktype->destroy(key);
-                       memset(&key->payload, 0xbd, sizeof(key->payload));
+                       memset(&key->payload, KEY_DESTROY, sizeof(key->payload));
                }
        }
 
index 329411cf8768ef6e8e90f387e35a65d2f3194782..d9ca15c109ccfaa167cafc8c39dec87f2a3e305d 100644 (file)
@@ -183,7 +183,7 @@ asmlinkage long sys_request_key(const char __user *_type,
        }
 
        /* do the search */
-       key = request_key_and_link(ktype, description, callout_info,
+       key = request_key_and_link(ktype, description, callout_info, NULL,
                                   key_ref_to_ptr(dest_ref),
                                   KEY_ALLOC_IN_QUOTA);
        if (IS_ERR(key)) {
index 58d1efd4fc2c66788788edcc2e5d90bd32e1dc10..f573ac189a0a6595b2184b43a9d54c3b01e0d5a0 100644 (file)
@@ -1,6 +1,6 @@
 /* request_key.c: request a key from userspace
  *
- * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -33,7 +33,8 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
  */
 static int call_sbin_request_key(struct key *key,
                                 struct key *authkey,
-                                const char *op)
+                                const char *op,
+                                void *aux)
 {
        struct task_struct *tsk = current;
        key_serial_t prkey, sskey;
@@ -127,6 +128,7 @@ error_alloc:
 static struct key *__request_key_construction(struct key_type *type,
                                              const char *description,
                                              const char *callout_info,
+                                             void *aux,
                                              unsigned long flags)
 {
        request_key_actor_t actor;
@@ -164,7 +166,7 @@ static struct key *__request_key_construction(struct key_type *type,
        actor = call_sbin_request_key;
        if (type->request_key)
                actor = type->request_key;
-       ret = actor(key, authkey, "create");
+       ret = actor(key, authkey, "create", aux);
        if (ret < 0)
                goto request_failed;
 
@@ -258,8 +260,9 @@ alloc_failed:
  */
 static struct key *request_key_construction(struct key_type *type,
                                            const char *description,
-                                           struct key_user *user,
                                            const char *callout_info,
+                                           void *aux,
+                                           struct key_user *user,
                                            unsigned long flags)
 {
        struct key_construction *pcons;
@@ -284,7 +287,7 @@ static struct key *request_key_construction(struct key_type *type,
        }
 
        /* see about getting userspace to construct the key */
-       key = __request_key_construction(type, description, callout_info,
+       key = __request_key_construction(type, description, callout_info, aux,
                                         flags);
  error:
        kleave(" = %p", key);
@@ -392,6 +395,7 @@ static void request_key_link(struct key *key, struct key *dest_keyring)
 struct key *request_key_and_link(struct key_type *type,
                                 const char *description,
                                 const char *callout_info,
+                                void *aux,
                                 struct key *dest_keyring,
                                 unsigned long flags)
 {
@@ -399,8 +403,9 @@ struct key *request_key_and_link(struct key_type *type,
        struct key *key;
        key_ref_t key_ref;
 
-       kenter("%s,%s,%s,%p,%lx",
-              type->name, description, callout_info, dest_keyring, flags);
+       kenter("%s,%s,%s,%p,%p,%lx",
+              type->name, description, callout_info, aux,
+              dest_keyring, flags);
 
        /* search all the process keyrings for a key */
        key_ref = search_process_keyrings(type, description, type->match,
@@ -433,8 +438,8 @@ struct key *request_key_and_link(struct key_type *type,
                        /* ask userspace (returns NULL if it waited on a key
                         * being constructed) */
                        key = request_key_construction(type, description,
-                                                      user, callout_info,
-                                                      flags);
+                                                      callout_info, aux,
+                                                      user, flags);
                        if (key)
                                break;
 
@@ -491,8 +496,27 @@ struct key *request_key(struct key_type *type,
                        const char *callout_info)
 {
        return request_key_and_link(type, description, callout_info, NULL,
-                                   KEY_ALLOC_IN_QUOTA);
+                                   NULL, KEY_ALLOC_IN_QUOTA);
 
 } /* end request_key() */
 
 EXPORT_SYMBOL(request_key);
+
+/*****************************************************************************/
+/*
+ * request a key with auxiliary data for the upcaller
+ * - search the process's keyrings
+ * - check the list of keys being created or updated
+ * - call out to userspace for a key if supplementary info was provided
+ */
+struct key *request_key_with_auxdata(struct key_type *type,
+                                    const char *description,
+                                    const char *callout_info,
+                                    void *aux)
+{
+       return request_key_and_link(type, description, callout_info, aux,
+                                   NULL, KEY_ALLOC_IN_QUOTA);
+
+} /* end request_key_with_auxdata() */
+
+EXPORT_SYMBOL(request_key_with_auxdata);
index ac7f2b2e39240024a70cfe06b464e93050447410..28832e689800b9c9250b54cc4c0be918adebb51d 100644 (file)
@@ -1532,8 +1532,9 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        /* Default to the current task SID. */
        bsec->sid = tsec->sid;
 
-       /* Reset create and sockcreate SID on execve. */
+       /* Reset fs, key, and sock SIDs on execve. */
        tsec->create_sid = 0;
+       tsec->keycreate_sid = 0;
        tsec->sockcreate_sid = 0;
 
        if (tsec->exec_sid) {
@@ -2586,9 +2587,10 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
        tsec2->osid = tsec1->osid;
        tsec2->sid = tsec1->sid;
 
-       /* Retain the exec, create, and sock SIDs across fork */
+       /* Retain the exec, fs, key, and sock SIDs across fork */
        tsec2->exec_sid = tsec1->exec_sid;
        tsec2->create_sid = tsec1->create_sid;
+       tsec2->keycreate_sid = tsec1->keycreate_sid;
        tsec2->sockcreate_sid = tsec1->sockcreate_sid;
 
        /* Retain ptracer SID across fork, if any.
index a682ea30f0c949bccd79c2199c5603c36498aa22..1f60797afa8a42afa0a52ffdd8506d0a796cf75c 100644 (file)
@@ -4,7 +4,8 @@
 obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ aoa/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/
+obj-$(CONFIG_SND_AOA) += aoa/
 
 ifeq ($(CONFIG_SND),y)
   obj-y += last.o
index a85194fe0b06119a7044009c1fd5aef50cd2c7e1..2f4334d19ccd2eb475e06cea9d61d0b47a6fbcba 100644 (file)
@@ -3,7 +3,8 @@ menu "Apple Onboard Audio driver"
 
 config SND_AOA
        tristate "Apple Onboard Audio driver"
-       depends on SOUND && SND_PCM
+       depends on SND
+       select SND_PCM
        ---help---
        This option enables the new driver for the various
        Apple Onboard Audio components.
index 2c6eb7784cc9164a3080f8e7b1e6cd200fadbaab..bab97547a052ee66278df503aefbcfb2f109251f 100644 (file)
@@ -207,6 +207,17 @@ static void ftr_handle_notify(void *data)
        mutex_unlock(&notif->mutex);
 }
 
+static void gpio_enable_dual_edge(int gpio)
+{
+       int v;
+
+       if (gpio == -1)
+               return;
+       v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0);
+       v |= 0x80; /* enable dual edge */
+       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio, v);
+}
+
 static void ftr_gpio_init(struct gpio_runtime *rt)
 {
        get_gpio("headphone-mute", NULL,
@@ -234,6 +245,10 @@ static void ftr_gpio_init(struct gpio_runtime *rt)
                                      &linein_detect_gpio,
                                      &linein_detect_gpio_activestate);
 
+       gpio_enable_dual_edge(headphone_detect_gpio);
+       gpio_enable_dual_edge(lineout_detect_gpio);
+       gpio_enable_dual_edge(linein_detect_gpio);
+
        get_irq(headphone_detect_node, &headphone_detect_irq);
        get_irq(lineout_detect_node, &lineout_detect_irq);
        get_irq(linein_detect_node, &linein_detect_irq);
index 04a7238e94946234e65348f09f2bb26e6ba54cca..cbc8a3b5cea4e3d638d936ad72782dba552e0121 100644 (file)
@@ -94,6 +94,7 @@ MODULE_ALIAS("sound-layout-82");
 MODULE_ALIAS("sound-layout-84");
 MODULE_ALIAS("sound-layout-86");
 MODULE_ALIAS("sound-layout-92");
+MODULE_ALIAS("sound-layout-96");
 
 /* onyx with all but microphone connected */
 static struct codec_connection onyx_connections_nomic[] = {
@@ -381,6 +382,13 @@ static struct layout layouts[] = {
                .connections = toonie_connections,
          },
        },
+       {
+         .layout_id = 96,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+       },
        /* unknown, untested, but this comes from Apple */
        { .layout_id = 41,
          .codecs[0] = {
@@ -479,12 +487,6 @@ static struct layout layouts[] = {
                .connections = onyx_connections_noheadphones,
          },
        },
-       { .layout_id = 96,
-         .codecs[0] = {
-               .name = "onyx",
-               .connections = onyx_connections_noheadphones,
-         },
-       },
        { .layout_id = 98,
          .codecs[0] = {
                .name = "toonie",
index d532d27a9f5476e64ac54e08968f17a6d8f78ada..7368b7ddfe0dd88f4f11f5973d8dfa186120c6d5 100644 (file)
@@ -1,6 +1,7 @@
 config SND_AOA_SOUNDBUS
        tristate "Apple Soundbus support"
-       depends on SOUND && SND_PCM && EXPERIMENTAL
+       depends on SOUND
+       select SND_PCM
        ---help---
        This option enables the generic driver for the soundbus
        support on Apple machines.
index 5f22d70fefc0fa114a7f9b12814f8c7a6b31b41e..6b18225672c7ae6227a8ebb206c9aaf6460cee00 100644 (file)
@@ -779,8 +779,9 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
        strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
        strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname));
        snprintf(card->longname, sizeof(card->longname),
-                "%s at 0x%08lx, irq %d",
-                card->shortname, dev->res.start, dev->irq[0]);
+                "%s at 0x%016llx, irq %d",
+                card->shortname, (unsigned long long)dev->res.start,
+                dev->irq[0]);
 
        aaci = card->private_data;
        mutex_init(&aaci->ac97_sem);
index 4262a1c8773191f072b48277a5f42eb2b5d19cb7..b2927523d79df9c7ad796049ebb8145fb537ac57 100644 (file)
@@ -122,8 +122,8 @@ config SND_SEQ_RTCTIMER_DEFAULT
          If in doubt, say Y.
 
 config SND_DYNAMIC_MINORS
-       bool "Dynamic device file minor numbers (EXPERIMENTAL)"
-       depends on SND && EXPERIMENTAL
+       bool "Dynamic device file minor numbers"
+       depends on SND
        help
          If you say Y here, the minor numbers of ALSA device files in
          /dev/snd/ are allocated dynamically.  This allows you to have
index 10c1772bf3ea3dbe9ff06960f945d06457112a35..340332c6d97337889e73927730747feecd6e37a6 100644 (file)
@@ -29,7 +29,6 @@
 #include <sound/info.h>
 #include <sound/version.h>
 #include <linux/proc_fs.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/mutex.h>
 #include <stdarg.h>
 
index 334579a9f268b692178ee301ec3103c4072d8981..d467b4f0ff2b18d50dae96e813a686f7a28821e6 100644 (file)
@@ -322,10 +322,8 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
        mutex_lock(&client->ports_mutex);
        write_lock_irqsave(&client->ports_lock, flags);
        if (! list_empty(&client->ports_list_head)) {
-               __list_add(&deleted_list,
-                          client->ports_list_head.prev,
-                          client->ports_list_head.next);
-               INIT_LIST_HEAD(&client->ports_list_head);
+               list_add(&deleted_list, &client->ports_list_head);
+               list_del_init(&client->ports_list_head);
        } else {
                INIT_LIST_HEAD(&deleted_list);
        }
index cd862728346cb03e74abe870f4a997c0e5fa6de7..264f2efd1af88ffc26b3b333d08e88a0dd6e19e1 100644 (file)
@@ -32,7 +32,6 @@
 #include <sound/control.h>
 #include <sound/initval.h>
 #include <linux/kmod.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/mutex.h>
 
 #define SNDRV_OS_MINORS 256
@@ -42,7 +41,6 @@ int snd_major;
 EXPORT_SYMBOL(snd_major);
 
 static int cards_limit = 1;
-static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO;
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
 MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards.");
@@ -51,10 +49,6 @@ module_param(major, int, 0444);
 MODULE_PARM_DESC(major, "Major # for sound driver.");
 module_param(cards_limit, int, 0444);
 MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards.");
-#ifdef CONFIG_DEVFS_FS
-module_param(device_mode, int, 0444);
-MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs.");
-#endif
 MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
 
 /* this one holds the actual max. card number currently available.
@@ -273,8 +267,6 @@ int snd_register_device(int type, struct snd_card *card, int dev,
                return minor;
        }
        snd_minors[minor] = preg;
-       if (type != SNDRV_DEVICE_TYPE_CONTROL || preg->card >= cards_limit)
-               devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name);
        if (card)
                device = card->dev;
        class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name);
@@ -314,9 +306,6 @@ int snd_unregister_device(int type, struct snd_card *card, int dev)
                return -EINVAL;
        }
 
-       if (mptr->type != SNDRV_DEVICE_TYPE_CONTROL ||
-           mptr->card >= cards_limit)                  /* created in sound.c */
-               devfs_remove("snd/%s", mptr->name);
        class_device_destroy(sound_class, MKDEV(major, minor));
 
        snd_minors[minor] = NULL;
@@ -411,24 +400,17 @@ int __exit snd_minor_info_done(void)
 
 static int __init alsa_sound_init(void)
 {
-       short controlnum;
-
        snd_major = major;
        snd_ecards_limit = cards_limit;
-       devfs_mk_dir("snd");
        if (register_chrdev(major, "alsa", &snd_fops)) {
                snd_printk(KERN_ERR "unable to register native major device number %d\n", major);
-               devfs_remove("snd");
                return -EIO;
        }
        if (snd_info_init() < 0) {
                unregister_chrdev(major, "alsa");
-               devfs_remove("snd");
                return -ENOMEM;
        }
        snd_info_minor_register();
-       for (controlnum = 0; controlnum < cards_limit; controlnum++)
-               devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum);
 #ifndef MODULE
        printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n");
 #endif
@@ -437,16 +419,10 @@ static int __init alsa_sound_init(void)
 
 static void __exit alsa_sound_exit(void)
 {
-       short controlnum;
-
-       for (controlnum = 0; controlnum < cards_limit; controlnum++)
-               devfs_remove("snd/controlC%d", controlnum);
-
        snd_info_minor_unregister();
        snd_info_done();
        if (unregister_chrdev(major, "alsa") != 0)
                snd_printk(KERN_ERR "unable to unregister major device number %d\n", major);
-       devfs_remove("snd");
 }
 
 module_init(alsa_sound_init)
index d3cbbb04758231940d21f2d43a2caa7bddf164cd..8b80024968be7d32f32e0b15fdfe5c1e6352425e 100644 (file)
@@ -160,8 +160,9 @@ static int __devinit snd_mpu401_pnp(int dev, struct pnp_dev *device,
                return -ENODEV;
        }
        if (pnp_port_len(device, 0) < IO_EXTENT) {
-               snd_printk(KERN_ERR "PnP port length is %ld, expected %d\n",
-                          pnp_port_len(device, 0), IO_EXTENT);
+               snd_printk(KERN_ERR "PnP port length is %llu, expected %d\n",
+                          (unsigned long long)pnp_port_len(device, 0),
+                          IO_EXTENT);
                return -ENODEV;
        }
        port[dev] = pnp_port_start(device, 0);
index 045e32a311e0406e4b795a89e29732d20282713b..dc7cc2001b74a572b67bc4d015e8e2f4f527f600 100644 (file)
@@ -34,7 +34,8 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx  AD/DA converters");
 MODULE_LICENSE("GPL");
 
-void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsigned char val)
+void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
+                      unsigned char val)
 {
        ak->ops.lock(ak, chip);
        ak->ops.write(ak, chip, reg, val);
@@ -52,6 +53,67 @@ void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsi
        ak->ops.unlock(ak, chip);
 }
 
+EXPORT_SYMBOL(snd_akm4xxx_write);
+
+/* reset procedure for AK4524 and AK4528 */
+static void ak4524_reset(struct snd_akm4xxx *ak, int state)
+{
+       unsigned int chip;
+       unsigned char reg, maxreg;
+
+       if (ak->type == SND_AK4528)
+               maxreg = 0x06;
+       else
+               maxreg = 0x08;
+       for (chip = 0; chip < ak->num_dacs/2; chip++) {
+               snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
+               if (state)
+                       continue;
+               /* DAC volumes */
+               for (reg = 0x04; reg < maxreg; reg++)
+                       snd_akm4xxx_write(ak, chip, reg,
+                                         snd_akm4xxx_get(ak, chip, reg));
+               if (ak->type == SND_AK4528)
+                       continue;
+               /* IPGA */
+               for (reg = 0x04; reg < 0x06; reg++)
+                       snd_akm4xxx_write(ak, chip, reg,
+                                         snd_akm4xxx_get_ipga(ak, chip, reg));
+       }
+}
+
+/* reset procedure for AK4355 and AK4358 */
+static void ak4355_reset(struct snd_akm4xxx *ak, int state)
+{
+       unsigned char reg;
+
+       if (state) {
+               snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
+               return;
+       }
+       for (reg = 0x00; reg < 0x0b; reg++)
+               if (reg != 0x01)
+                       snd_akm4xxx_write(ak, 0, reg,
+                                         snd_akm4xxx_get(ak, 0, reg));
+       snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
+}
+
+/* reset procedure for AK4381 */
+static void ak4381_reset(struct snd_akm4xxx *ak, int state)
+{
+       unsigned int chip;
+       unsigned char reg;
+
+       for (chip = 0; chip < ak->num_dacs/2; chip++) {
+               snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
+               if (state)
+                       continue;
+               for (reg = 0x01; reg < 0x05; reg++)
+                       snd_akm4xxx_write(ak, chip, reg,
+                                         snd_akm4xxx_get(ak, chip, reg));
+       }
+}
+
 /*
  * reset the AKM codecs
  * @state: 1 = reset codec, 0 = restore the registers
@@ -60,52 +122,26 @@ void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsi
  */
 void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
 {
-       unsigned int chip;
-       unsigned char reg;
-       
        switch (ak->type) {
        case SND_AK4524:
        case SND_AK4528:
-               for (chip = 0; chip < ak->num_dacs/2; chip++) {
-                       snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
-                       if (state)
-                               continue;
-                       /* DAC volumes */
-                       for (reg = 0x04; reg < (ak->type == SND_AK4528 ? 0x06 : 0x08); reg++)
-                               snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg));
-                       if (ak->type == SND_AK4528)
-                               continue;
-                       /* IPGA */
-                       for (reg = 0x04; reg < 0x06; reg++)
-                               snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get_ipga(ak, chip, reg));
-               }
+               ak4524_reset(ak, state);
                break;
        case SND_AK4529:
                /* FIXME: needed for ak4529? */
                break;
        case SND_AK4355:
        case SND_AK4358:
-               if (state) {
-                       snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
-                       return;
-               }
-               for (reg = 0x00; reg < 0x0b; reg++)
-                       if (reg != 0x01)
-                               snd_akm4xxx_write(ak, 0, reg, snd_akm4xxx_get(ak, 0, reg));
-               snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
+               ak4355_reset(ak, state);
                break;
        case SND_AK4381:
-               for (chip = 0; chip < ak->num_dacs/2; chip++) {
-                       snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
-                       if (state)
-                               continue;
-                       for (reg = 0x01; reg < 0x05; reg++)
-                               snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg));
-               }
+               ak4381_reset(ak, state);
                break;
        }
 }
 
+EXPORT_SYMBOL(snd_akm4xxx_reset);
+
 /*
  * initialize all the ak4xxx chips
  */
@@ -153,7 +189,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
        };
        static unsigned char inits_ak4355[] = {
                0x01, 0x02, /* 1: reset and soft-mute */
-               0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */
+               0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
+                            * disable DZF, sharp roll-off, RSTN#=0 */
                0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
                // 0x02, 0x2e, /* quad speed */
                0x03, 0x01, /* 3: de-emphasis off */
@@ -169,7 +206,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
        };
        static unsigned char inits_ak4358[] = {
                0x01, 0x02, /* 1: reset and soft-mute */
-               0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */
+               0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
+                            * disable DZF, sharp roll-off, RSTN#=0 */
                0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
                // 0x02, 0x2e, /* quad speed */
                0x03, 0x01, /* 3: de-emphasis off */
@@ -187,7 +225,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
        };
        static unsigned char inits_ak4381[] = {
                0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
-               0x01, 0x02, /* 1: de-emphasis off, normal speed, sharp roll-off, DZF off */
+               0x01, 0x02, /* 1: de-emphasis off, normal speed,
+                            * sharp roll-off, DZF off */
                // 0x01, 0x12, /* quad speed */
                0x02, 0x00, /* 2: DZF disabled */
                0x03, 0x00, /* 3: LATT 0 */
@@ -239,12 +278,15 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
        }
 }
 
+EXPORT_SYMBOL(snd_akm4xxx_init);
+
 #define AK_GET_CHIP(val)               (((val) >> 8) & 0xff)
 #define AK_GET_ADDR(val)               ((val) & 0xff)
 #define AK_GET_SHIFT(val)              (((val) >> 16) & 0x7f)
 #define AK_GET_INVERT(val)             (((val) >> 23) & 1)
 #define AK_GET_MASK(val)               (((val) >> 24) & 0xff)
-#define AK_COMPOSE(chip,addr,shift,mask) (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
+#define AK_COMPOSE(chip,addr,shift,mask) \
+       (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
 #define AK_INVERT                      (1<<23)
 
 static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
@@ -292,6 +334,64 @@ static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = mask;
+       return 0;
+}
+
+static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+       int chip = AK_GET_CHIP(kcontrol->private_value);
+       int addr = AK_GET_ADDR(kcontrol->private_value);
+       int invert = AK_GET_INVERT(kcontrol->private_value);
+       unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+       unsigned char val = snd_akm4xxx_get(ak, chip, addr);
+       
+       ucontrol->value.integer.value[0] = invert ? mask - val : val;
+
+       val = snd_akm4xxx_get(ak, chip, addr+1);
+       ucontrol->value.integer.value[1] = invert ? mask - val : val;
+
+       return 0;
+}
+
+static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+       int chip = AK_GET_CHIP(kcontrol->private_value);
+       int addr = AK_GET_ADDR(kcontrol->private_value);
+       int invert = AK_GET_INVERT(kcontrol->private_value);
+       unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+       unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
+       int change0, change1;
+
+       if (invert)
+               nval = mask - nval;
+       change0 = snd_akm4xxx_get(ak, chip, addr) != nval;
+       if (change0)
+               snd_akm4xxx_write(ak, chip, addr, nval);
+
+       nval = ucontrol->value.integer.value[1] % (mask+1);
+       if (invert)
+               nval = mask - nval;
+       change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval;
+       if (change1)
+               snd_akm4xxx_write(ak, chip, addr+1, nval);
+
+
+       return change0 || change1;
+}
+
 static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_info *uinfo)
 {
@@ -308,7 +408,8 @@ static int snd_akm4xxx_ipga_gain_get(struct snd_kcontrol *kcontrol,
        struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
        int chip = AK_GET_CHIP(kcontrol->private_value);
        int addr = AK_GET_ADDR(kcontrol->private_value);
-       ucontrol->value.integer.value[0] = snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f;
+       ucontrol->value.integer.value[0] =
+               snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f;
        return 0;
 }
 
@@ -336,7 +437,8 @@ static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
        uinfo->value.enumerated.items = 4;
        if (uinfo->value.enumerated.item >= 4)
                uinfo->value.enumerated.item = 3;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       strcpy(uinfo->value.enumerated.name,
+              texts[uinfo->value.enumerated.item]);
        return 0;
 }
 
@@ -347,7 +449,8 @@ static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
        int chip = AK_GET_CHIP(kcontrol->private_value);
        int addr = AK_GET_ADDR(kcontrol->private_value);
        int shift = AK_GET_SHIFT(kcontrol->private_value);
-       ucontrol->value.enumerated.item[0] = (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
+       ucontrol->value.enumerated.item[0] =
+               (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
        return 0;
 }
 
@@ -361,7 +464,8 @@ static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
        unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
        int change;
        
-       nval = (nval << shift) | (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
+       nval = (nval << shift) |
+               (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
        change = snd_akm4xxx_get(ak, chip, addr) != nval;
        if (change)
                snd_akm4xxx_write(ak, chip, addr, nval);
@@ -377,51 +481,86 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
        unsigned int idx, num_emphs;
        struct snd_kcontrol *ctl;
        int err;
+       int mixer_ch = 0;
+       int num_stereo;
 
        ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
        if (! ctl)
                return -ENOMEM;
 
-       for (idx = 0; idx < ak->num_dacs; ++idx) {
+       for (idx = 0; idx < ak->num_dacs; ) {
                memset(ctl, 0, sizeof(*ctl));
-               strcpy(ctl->id.name, "DAC Volume");
-               ctl->id.index = idx + ak->idx_offset * 2;
+               if (ak->channel_names == NULL) {
+                       strcpy(ctl->id.name, "DAC Volume");
+                       num_stereo = 1;
+                       ctl->id.index = mixer_ch + ak->idx_offset * 2;
+               } else {
+                       strcpy(ctl->id.name, ak->channel_names[mixer_ch]);
+                       num_stereo = ak->num_stereo[mixer_ch];
+                       ctl->id.index = 0;
+               }
                ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
                ctl->count = 1;
-               ctl->info = snd_akm4xxx_volume_info;
-               ctl->get = snd_akm4xxx_volume_get;
-               ctl->put = snd_akm4xxx_volume_put;
+               if (num_stereo == 2) {
+                       ctl->info = snd_akm4xxx_stereo_volume_info;
+                       ctl->get = snd_akm4xxx_stereo_volume_get;
+                       ctl->put = snd_akm4xxx_stereo_volume_put;
+               } else {
+                       ctl->info = snd_akm4xxx_volume_info;
+                       ctl->get = snd_akm4xxx_volume_get;
+                       ctl->put = snd_akm4xxx_volume_put;
+               }
                switch (ak->type) {
                case SND_AK4524:
-                       ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */
+                       /* register 6 & 7 */
+                       ctl->private_value =
+                               AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127);
                        break;
                case SND_AK4528:
-                       ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
+                       /* register 4 & 5 */
+                       ctl->private_value =
+                               AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127);
                        break;
                case SND_AK4529: {
-                       int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */
-                       ctl->private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
+                       /* registers 2-7 and b,c */
+                       int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
+                       ctl->private_value =
+                               AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
                        break;
                }
                case SND_AK4355:
-                       ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
+                       /* register 4-9, chip #0 only */
+                       ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255);
                        break;
                case SND_AK4358:
                        if (idx >= 6)
-                               ctl->private_value = AK_COMPOSE(0, idx + 5, 0, 255); /* register 4-9, chip #0 only */
+                               /* register 4-9, chip #0 only */
+                               ctl->private_value =
+                                       AK_COMPOSE(0, idx + 5, 0, 255);
                        else
-                               ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
+                               /* register 4-9, chip #0 only */
+                               ctl->private_value =
+                                       AK_COMPOSE(0, idx + 4, 0, 255);
                        break;
                case SND_AK4381:
-                       ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */
+                       /* register 3 & 4 */
+                       ctl->private_value =
+                               AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
                        break;
                default:
                        err = -EINVAL;
                        goto __error;
                }
+
                ctl->private_data = ak;
-               if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
+               err = snd_ctl_add(ak->card,
+                                 snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
+                                             SNDRV_CTL_ELEM_ACCESS_WRITE));
+               if (err < 0)
                        goto __error;
+
+               idx += num_stereo;
+               mixer_ch++;
        }
        for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) {
                memset(ctl, 0, sizeof(*ctl));
@@ -432,9 +571,14 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
                ctl->info = snd_akm4xxx_volume_info;
                ctl->get = snd_akm4xxx_volume_get;
                ctl->put = snd_akm4xxx_volume_put;
-               ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
+               /* register 4 & 5 */
+               ctl->private_value =
+                       AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127);
                ctl->private_data = ak;
-               if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
+               err = snd_ctl_add(ak->card,
+                                 snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
+                                             SNDRV_CTL_ELEM_ACCESS_WRITE));
+               if (err < 0)
                        goto __error;
 
                memset(ctl, 0, sizeof(*ctl));
@@ -445,9 +589,13 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
                ctl->info = snd_akm4xxx_ipga_gain_info;
                ctl->get = snd_akm4xxx_ipga_gain_get;
                ctl->put = snd_akm4xxx_ipga_gain_put;
-               ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */
+               /* register 4 & 5 */
+               ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0);
                ctl->private_data = ak;
-               if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
+               err = snd_ctl_add(ak->card,
+                                 snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
+                                             SNDRV_CTL_ELEM_ACCESS_WRITE));
+               if (err < 0)
                        goto __error;
        }
        if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
@@ -466,11 +614,13 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
                switch (ak->type) {
                case SND_AK4524:
                case SND_AK4528:
-                       ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */
+                       /* register 3 */
+                       ctl->private_value = AK_COMPOSE(idx, 3, 0, 0);
                        break;
                case SND_AK4529: {
                        int shift = idx == 3 ? 6 : (2 - idx) * 2;
-                       ctl->private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */
+                       /* register 8 with shift */
+                       ctl->private_value = AK_COMPOSE(0, 8, shift, 0);
                        break;
                }
                case SND_AK4355:
@@ -482,7 +632,10 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
                        break;
                }
                ctl->private_data = ak;
-               if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
+               err = snd_ctl_add(ak->card,
+                                 snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
+                                             SNDRV_CTL_ELEM_ACCESS_WRITE));
+               if (err < 0)
                        goto __error;
        }
        err = 0;
@@ -492,6 +645,8 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
        return err;
 }
 
+EXPORT_SYMBOL(snd_akm4xxx_build_controls);
+
 static int __init alsa_akm4xxx_module_init(void)
 {
        return 0;
@@ -503,8 +658,3 @@ static void __exit alsa_akm4xxx_module_exit(void)
         
 module_init(alsa_akm4xxx_module_init)
 module_exit(alsa_akm4xxx_module_exit)
-
-EXPORT_SYMBOL(snd_akm4xxx_write);
-EXPORT_SYMBOL(snd_akm4xxx_reset);
-EXPORT_SYMBOL(snd_akm4xxx_init);
-EXPORT_SYMBOL(snd_akm4xxx_build_controls);
index e6945db8ed1b8a2fcd4b877712b96db8ff791c98..af60b0bc8115f59986b0be019adc050f8695f0cc 100644 (file)
@@ -2088,7 +2088,8 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
                kfree(cfg);
                return -EAGAIN;
        }
-       snd_printdd("pnp: port=0x%lx\n", pnp_port_start(acard->devc, 0));
+       snd_printdd("pnp: port=0x%llx\n",
+                       (unsigned long long)pnp_port_start(acard->devc, 0));
        /* PnP initialization */
        pdev = acard->dev;
        pnp_init_resource_table(cfg);
index 866300f2acbbd930cda9d0c92217919b1be58faa..c1c86e0fa56df0056b7a18cb2586fc5a7dd13242 100644 (file)
@@ -611,10 +611,10 @@ static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
        if (dma2[dev] >= 0)
                dma2[dev] = pnp_dma(pdev, 1);
        irq[dev] = pnp_irq(pdev, 0);
-       snd_printdd("isapnp IW: sb port=0x%lx, gf1 port=0x%lx, codec port=0x%lx\n",
-                               pnp_port_start(pdev, 0),
-                               pnp_port_start(pdev, 1),
-                               pnp_port_start(pdev, 2));
+       snd_printdd("isapnp IW: sb port=0x%llx, gf1 port=0x%llx, codec port=0x%llx\n",
+                       (unsigned long long)pnp_port_start(pdev, 0),
+                       (unsigned long long)pnp_port_start(pdev, 1),
+                       (unsigned long long)pnp_port_start(pdev, 2));
        snd_printdd("isapnp IW: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
 #ifdef SNDRV_STB
        /* Tone Control initialization */
index 7f7f05fa518afa78cd228b3f9a677215b74a873b..d64e67f2bafa3ef2537c03a703ff800d2b6ac8a8 100644 (file)
@@ -327,7 +327,8 @@ static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
                        goto __wt_error; 
                } 
                awe_port[dev] = pnp_port_start(pdev, 0);
-               snd_printdd("pnp SB16: wavetable port=0x%lx\n", pnp_port_start(pdev, 0));
+               snd_printdd("pnp SB16: wavetable port=0x%llx\n",
+                               (unsigned long long)pnp_port_start(pdev, 0));
        } else {
 __wt_error:
                if (pdev) {
index 3b8cdbca263665e53eca3f06b96c353912f6a218..f4980ca5c05c86d9f4cbd8c86c885f2bd35af09c 100644 (file)
@@ -493,6 +493,19 @@ config SOUND_CS4232
          See <file:Documentation/sound/oss/CS4232> for more information on
          configuring this card.
 
+config SOUND_SSCAPE
+       tristate "Ensoniq SoundScape support"
+       depends on SOUND_OSS
+       help
+         Answer Y if you have a sound card based on the Ensoniq SoundScape
+         chipset. Such cards are being manufactured at least by Ensoniq, Spea
+         and Reveal (Reveal makes also other cards).
+
+         If you compile the driver into the kernel, you have to add
+         "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command
+         line.
+
+
 config SOUND_VMIDI
        tristate "Loopback MIDI device support"
        depends on SOUND_OSS
index c7f86f09c28da1979a5c0e6de7cfde38fd1309d5..80f6c08e26e7fa73d40a9a8ee24e818d98e08355 100644 (file)
@@ -405,7 +405,7 @@ static const struct pnp_device_id cs4232_pnp_table[] = {
 
 MODULE_DEVICE_TABLE(pnp, cs4232_pnp_table);
 
-static int cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+static int __init cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 {
        struct address_info *isapnpcfg;
 
index 0294eec8ad9035ee621f516df74d692bab95faff..44e578098d76e77768ea6a872ff077eb5e89be85 100644 (file)
@@ -2035,8 +2035,9 @@ forte_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
        
        pci_set_drvdata (pci_dev, chip);
 
-       printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%04lX IRQ %u\n", 
-               chip->iobase, pci_resource_end (pci_dev, 0), chip->irq);
+       printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%16llX IRQ %u\n",
+               chip->iobase, (unsigned long long)pci_resource_end (pci_dev, 0),
+               chip->irq);
 
        /* Power it up */
        if ((ret = forte_chip_init (chip)) == 0)
index d33bb464f70e9a536a3448fdd7f69ae181bac0b7..a332899489021a870ad67face6268f6f690197ff 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/wait.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/major.h>
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
@@ -564,9 +563,6 @@ static int __init oss_init(void)
        sound_dmap_flag = (dmabuf > 0 ? 1 : 0);
 
        for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) {
-               devfs_mk_cdev(MKDEV(SOUND_MAJOR, dev_list[i].minor),
-                               S_IFCHR | dev_list[i].mode,
-                               "sound/%s", dev_list[i].name);
                class_device_create(sound_class, NULL,
                                    MKDEV(SOUND_MAJOR, dev_list[i].minor),
                                    NULL, "%s", dev_list[i].name);
@@ -574,15 +570,10 @@ static int __init oss_init(void)
                if (!dev_list[i].num)
                        continue;
 
-               for (j = 1; j < *dev_list[i].num; j++) {
-                       devfs_mk_cdev(MKDEV(SOUND_MAJOR,
-                                               dev_list[i].minor + (j*0x10)),
-                                       S_IFCHR | dev_list[i].mode,
-                                       "sound/%s%d", dev_list[i].name, j);
+               for (j = 1; j < *dev_list[i].num; j++)
                        class_device_create(sound_class, NULL,
                                            MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)),
                                            NULL, "%s%d", dev_list[i].name, j);
-               }
        }
 
        if (sound_nblocks >= 1024)
@@ -596,14 +587,11 @@ static void __exit oss_cleanup(void)
        int i, j;
 
        for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) {
-               devfs_remove("sound/%s", dev_list[i].name);
                class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor));
                if (!dev_list[i].num)
                        continue;
-               for (j = 1; j < *dev_list[i].num; j++) {
-                       devfs_remove("sound/%s%d", dev_list[i].name, j);
+               for (j = 1; j < *dev_list[i].num; j++)
                        class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)));
-               }
        }
        
        unregister_sound_special(1);
index 1a921ee71aba2d567c5e48d186343905fa981550..29a6e0cff79f793557f9ee49d7dae200efbf2018 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
+#include <linux/poison.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
@@ -308,7 +309,7 @@ struct via_info {
        unsigned sixchannel: 1; /* 8233/35 with 6 channel support */
        unsigned volume: 1;
 
-       int locked_rate : 1;
+       unsigned locked_rate : 1;
        
        int mixer_vol;          /* 8233/35 volume  - not yet implemented */
 
@@ -3522,7 +3523,7 @@ err_out_have_mixer:
 
 err_out_kfree:
 #ifndef VIA_NDEBUG
-       memset (card, 0xAB, sizeof (*card)); /* poison memory */
+       memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
 #endif
        kfree (card);
 
@@ -3559,7 +3560,7 @@ static void __devexit via_remove_one (struct pci_dev *pdev)
        via_ac97_cleanup (card);
 
 #ifndef VIA_NDEBUG
-       memset (card, 0xAB, sizeof (*card)); /* poison memory */
+       memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
 #endif
        kfree (card);
 
index d37346b12dc0804a045ac40ba348643087ee0745..23e54cedfd4a19c8c49915aa24f41e531535a68a 100644 (file)
@@ -233,6 +233,143 @@ config SND_CS5535AUDIO
          To compile this driver as a module, choose M here: the module
          will be called snd-cs5535audio.
 
+config SND_DARLA20
+       tristate "(Echoaudio) Darla20"
+       depends on SND
+       depends on FW_LOADER
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Darla.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-darla20
+
+config SND_GINA20
+       tristate "(Echoaudio) Gina20"
+       depends on SND
+       depends on FW_LOADER
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Gina.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-gina20
+
+config SND_LAYLA20
+       tristate "(Echoaudio) Layla20"
+       depends on SND
+       depends on FW_LOADER
+       select SND_RAWMIDI
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Layla.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-layla20
+
+config SND_DARLA24
+       tristate "(Echoaudio) Darla24"
+       depends on SND
+       depends on FW_LOADER
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Darla24.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-darla24
+
+config SND_GINA24
+       tristate "(Echoaudio) Gina24"
+       depends on SND
+       depends on FW_LOADER
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Gina24.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-gina24
+
+config SND_LAYLA24
+       tristate "(Echoaudio) Layla24"
+       depends on SND
+       depends on FW_LOADER
+       select SND_RAWMIDI
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Layla24.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-layla24
+
+config SND_MONA
+       tristate "(Echoaudio) Mona"
+       depends on SND
+       depends on FW_LOADER
+       select SND_RAWMIDI
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Mona.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-mona
+
+config SND_MIA
+       tristate "(Echoaudio) Mia"
+       depends on SND
+       depends on FW_LOADER
+       select SND_RAWMIDI
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Mia and Mia-midi.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-mia
+
+config SND_ECHO3G
+       tristate "(Echoaudio) 3G cards"
+       depends on SND
+       depends on FW_LOADER
+       select SND_RAWMIDI
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Gina3G and Layla3G.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-echo3g
+
+config SND_INDIGO
+       tristate "(Echoaudio) Indigo"
+       depends on SND
+       depends on FW_LOADER
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Indigo.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-indigo
+
+config SND_INDIGOIO
+       tristate "(Echoaudio) Indigo IO"
+       depends on SND
+       depends on FW_LOADER
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Indigo IO.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-indigoio
+
+config SND_INDIGODJ
+       tristate "(Echoaudio) Indigo DJ"
+       depends on SND
+       depends on FW_LOADER
+       select SND_PCM
+       help
+         Say 'Y' or 'M' to include support for Echoaudio Indigo DJ.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-indigodj
+
 config SND_EMU10K1
        tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)"
        depends on SND
@@ -420,8 +557,8 @@ config SND_INTEL8X0
          will be called snd-intel8x0.
 
 config SND_INTEL8X0M
-       tristate "Intel/SiS/nVidia/AMD MC97 Modem (EXPERIMENTAL)"
-       depends on SND && EXPERIMENTAL
+       tristate "Intel/SiS/nVidia/AMD MC97 Modem"
+       depends on SND
        select SND_AC97_CODEC
        help
          Say Y here to include support for the integrated MC97 modem on
index cba5105aafeae000b55323e4009cb4ee23bfcbcf..e06736da9ef196e8fc766d2c2c96a8f7258ec94d 100644 (file)
@@ -57,6 +57,7 @@ obj-$(CONFIG_SND) += \
        ca0106/ \
        cs46xx/ \
        cs5535audio/ \
+       echoaudio/ \
        emu10k1/ \
        hda/ \
        ice1712/ \
index 7f197c780816819425a4e49b018b49b57af527f2..094cfc1f3a190157b7bd7c0e3436cf00a9dcf858 100644 (file)
@@ -1824,6 +1824,8 @@ static const struct snd_kcontrol_new snd_ac97_ad1888_controls[] = {
                .get = snd_ac97_ad1888_lohpsel_get,
                .put = snd_ac97_ad1888_lohpsel_put
        },
+       AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1),
+       AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
        AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
index c33642d8d9a11e37e56e762b3342e4d660b8ae5c..497ed6b200608e8331fb3dd42656ebe05dca6c1d 100644 (file)
@@ -888,8 +888,9 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci,
 
        strcpy(card->driver, "Bt87x");
        sprintf(card->shortname, "Brooktree Bt%x", pci->device);
-       sprintf(card->longname, "%s at %#lx, irq %i",
-               card->shortname, pci_resource_start(pci, 0), chip->irq);
+       sprintf(card->longname, "%s at %#llx, irq %i",
+               card->shortname, (unsigned long long)pci_resource_start(pci, 0),
+               chip->irq);
        strcpy(card->mixername, "Bt87x");
 
        err = snd_card_register(card);
diff --git a/sound/pci/echoaudio/Makefile b/sound/pci/echoaudio/Makefile
new file mode 100644 (file)
index 0000000..7b576ae
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# Makefile for ALSA Echoaudio soundcard drivers
+# Copyright (c) 2003 by Giuliano Pochini <pochini@shiny.it>
+#
+
+snd-darla20-objs := darla20.o
+snd-gina20-objs := gina20.o
+snd-layla20-objs := layla20.o
+snd-darla24-objs := darla24.o
+snd-gina24-objs := gina24.o
+snd-layla24-objs := layla24.o
+snd-mona-objs := mona.o
+snd-mia-objs := mia.o
+snd-echo3g-objs := echo3g.o
+snd-indigo-objs := indigo.o
+snd-indigoio-objs := indigoio.o
+snd-indigodj-objs := indigodj.o
+
+obj-$(CONFIG_SND_DARLA20) += snd-darla20.o
+obj-$(CONFIG_SND_GINA20) += snd-gina20.o
+obj-$(CONFIG_SND_LAYLA20) += snd-layla20.o
+obj-$(CONFIG_SND_DARLA24) += snd-darla24.o
+obj-$(CONFIG_SND_GINA24) += snd-gina24.o
+obj-$(CONFIG_SND_LAYLA24) += snd-layla24.o
+obj-$(CONFIG_SND_MONA) += snd-mona.o
+obj-$(CONFIG_SND_MIA) += snd-mia.o
+obj-$(CONFIG_SND_ECHO3G) += snd-echo3g.o
+obj-$(CONFIG_SND_INDIGO) += snd-indigo.o
+obj-$(CONFIG_SND_INDIGOIO) += snd-indigoio.o
+obj-$(CONFIG_SND_INDIGODJ) += snd-indigodj.o
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c
new file mode 100644 (file)
index 0000000..b7108e2
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define ECHOGALS_FAMILY
+#define ECHOCARD_DARLA20
+#define ECHOCARD_NAME "Darla20"
+#define ECHOCARD_HAS_MONITOR
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 0 */
+#define PX_ANALOG_IN   8       /* 2 */
+#define PX_DIGITAL_IN  10      /* 0 */
+#define PX_NUM         10
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 8 */
+#define BX_DIGITAL_OUT 8       /* 0 */
+#define BX_ANALOG_IN   8       /* 2 */
+#define BX_DIGITAL_IN  10      /* 0 */
+#define BX_NUM         10
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_DARLA20_DSP 0
+
+static const struct firmware card_fw[] = {
+       {0, "darla20_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0},      /* DSP 56301 Darla20 rev.0 */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+       .rate_min = 44100,
+       .rate_max = 48000,
+       .channels_min = 1,
+       .channels_max = 2,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+       /* One page (4k) contains 512 instructions. I don't know if the hw
+       supports lists longer than this. In this case periods_max=220 is a
+       safe limit to make sure the list never exceeds 512 instructions. */
+};
+
+
+#include "darla20_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c
new file mode 100644 (file)
index 0000000..4159e3b
--- /dev/null
@@ -0,0 +1,125 @@
+/***************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Darla20\n"));
+       snd_assert((subdevice_id & 0xfff0) == DARLA20, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_DARLA20_DSP];
+       chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
+       chip->clock_state = GD_CLOCK_UNDEF;
+       /* Since this card has no ASIC, mark it as loaded so everything
+          works OK */
+       chip->asic_loaded = TRUE;
+       chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+/* The Darla20 has no external clock sources */
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       return ECHO_CLOCK_BIT_INTERNAL;
+}
+
+
+
+/* The Darla20 has no ASIC. Just do nothing */
+static int load_asic(struct echoaudio *chip)
+{
+       return 0;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u8 clock_state, spdif_status;
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       switch (rate) {
+       case 44100:
+               clock_state = GD_CLOCK_44;
+               spdif_status = GD_SPDIF_STATUS_44;
+               break;
+       case 48000:
+               clock_state = GD_CLOCK_48;
+               spdif_status = GD_SPDIF_STATUS_48;
+               break;
+       default:
+               clock_state = GD_CLOCK_NOCHANGE;
+               spdif_status = GD_SPDIF_STATUS_NOCHANGE;
+               break;
+       }
+
+       if (chip->clock_state == clock_state)
+               clock_state = GD_CLOCK_NOCHANGE;
+       if (spdif_status == chip->spdif_status)
+               spdif_status = GD_SPDIF_STATUS_NOCHANGE;
+
+       chip->comm_page->sample_rate = cpu_to_le32(rate);
+       chip->comm_page->gd_clock_state = clock_state;
+       chip->comm_page->gd_spdif_status = spdif_status;
+       chip->comm_page->gd_resampler_state = 3;        /* magic number - should always be 3 */
+
+       /* Save the new audio state if it changed */
+       if (clock_state != GD_CLOCK_NOCHANGE)
+               chip->clock_state = clock_state;
+       if (spdif_status != GD_SPDIF_STATUS_NOCHANGE)
+               chip->spdif_status = spdif_status;
+       chip->sample_rate = rate;
+
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
+}
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c
new file mode 100644 (file)
index 0000000..e59a982
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define ECHOGALS_FAMILY
+#define ECHOCARD_DARLA24
+#define ECHOCARD_NAME "Darla24"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_EXTERNAL_CLOCK
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 0 */
+#define PX_ANALOG_IN   8       /* 2 */
+#define PX_DIGITAL_IN  10      /* 0 */
+#define PX_NUM         10
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 8 */
+#define BX_DIGITAL_OUT 8       /* 0 */
+#define BX_ANALOG_IN   8       /* 2 */
+#define BX_DIGITAL_IN  10      /* 0 */
+#define BX_NUM         10
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_DARLA24_DSP 0
+
+static const struct firmware card_fw[] = {
+       {0, "darla24_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0},      /* DSP 56301 Darla24 rev.0 */
+       {0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0},      /* DSP 56301 Darla24 rev.1 */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_8000_48000 |
+                       SNDRV_PCM_RATE_88200 |
+                       SNDRV_PCM_RATE_96000,
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 1,
+       .channels_max = 8,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+       /* One page (4k) contains 512 instructions. I don't know if the hw
+       supports lists longer than this. In this case periods_max=220 is a
+       safe limit to make sure the list never exceeds 512 instructions. */
+};
+
+
+#include "darla24_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c
new file mode 100644 (file)
index 0000000..79938ee
--- /dev/null
@@ -0,0 +1,156 @@
+/***************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Darla24\n"));
+       snd_assert((subdevice_id & 0xfff0) == DARLA24, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_DARLA24_DSP];
+       /* Since this card has no ASIC, mark it as loaded so everything
+          works OK */
+       chip->asic_loaded = TRUE;
+       chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
+               ECHO_CLOCK_BIT_ESYNC;
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       u32 clocks_from_dsp, clock_bits;
+
+       /* Map the DSP clock detect bits to the generic driver clock
+          detect bits */
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       clock_bits = ECHO_CLOCK_BIT_INTERNAL;
+
+       if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_ESYNC)
+               clock_bits |= ECHO_CLOCK_BIT_ESYNC;
+
+       return clock_bits;
+}
+
+
+
+/* The Darla24 has no ASIC. Just do nothing */
+static int load_asic(struct echoaudio *chip)
+{
+       return 0;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u8 clock;
+
+       switch (rate) {
+       case 96000:
+               clock = GD24_96000;
+               break;
+       case 88200:
+               clock = GD24_88200;
+               break;
+       case 48000:
+               clock = GD24_48000;
+               break;
+       case 44100:
+               clock = GD24_44100;
+               break;
+       case 32000:
+               clock = GD24_32000;
+               break;
+       case 22050:
+               clock = GD24_22050;
+               break;
+       case 16000:
+               clock = GD24_16000;
+               break;
+       case 11025:
+               clock = GD24_11025;
+               break;
+       case 8000:
+               clock = GD24_8000;
+               break;
+       default:
+               DE_ACT(("set_sample_rate: Error, invalid sample rate %d\n",
+                       rate));
+               return -EINVAL;
+       }
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+       chip->sample_rate = rate;
+
+       /* Override the sample rate if this card is set to Echo sync. */
+       if (chip->input_clock == ECHO_CLOCK_ESYNC)
+               clock = GD24_EXT_SYNC;
+
+       chip->comm_page->sample_rate = cpu_to_le32(rate);       /* ignored by the DSP ? */
+       chip->comm_page->gd_clock_state = clock;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
+}
+
+
+
+static int set_input_clock(struct echoaudio *chip, u16 clock)
+{
+       snd_assert(clock == ECHO_CLOCK_INTERNAL ||
+                  clock == ECHO_CLOCK_ESYNC, return -EINVAL);
+       chip->input_clock = clock;
+       return set_sample_rate(chip, chip->sample_rate);
+}
+
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c
new file mode 100644 (file)
index 0000000..12099fe
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define ECHO3G_FAMILY
+#define ECHOCARD_ECHO3G
+#define ECHOCARD_NAME "Echo3G"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_ASIC
+#define ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_DIGITAL_IO
+#define ECHOCARD_HAS_DIGITAL_MODE_SWITCH
+#define ECHOCARD_HAS_ADAT      6
+#define ECHOCARD_HAS_EXTERNAL_CLOCK
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+#define ECHOCARD_HAS_MIDI
+#define ECHOCARD_HAS_PHANTOM_POWER
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0
+#define PX_DIGITAL_OUT chip->px_digital_out
+#define PX_ANALOG_IN   chip->px_analog_in
+#define PX_DIGITAL_IN  chip->px_digital_in
+#define PX_NUM         chip->px_num
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0
+#define BX_DIGITAL_OUT chip->bx_digital_out
+#define BX_ANALOG_IN   chip->bx_analog_in
+#define BX_DIGITAL_IN  chip->bx_digital_in
+#define BX_NUM         chip->bx_num
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_361_LOADER  0
+#define FW_ECHO3G_DSP  1
+#define FW_3G_ASIC     2
+
+static const struct firmware card_fw[] = {
+       {0, "loader_dsp.fw"},
+       {0, "echo3g_dsp.fw"},
+       {0, "3g_asic.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0},      /* Echo 3G */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_32000 |
+                       SNDRV_PCM_RATE_44100 |
+                       SNDRV_PCM_RATE_48000 |
+                       SNDRV_PCM_RATE_88200 |
+                       SNDRV_PCM_RATE_96000 |
+                       SNDRV_PCM_RATE_CONTINUOUS,
+       .rate_min = 32000,
+       .rate_max = 100000,
+       .channels_min = 1,
+       .channels_max = 8,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+};
+
+#include "echo3g_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio_3g.c"
+#include "echoaudio.c"
+#include "midi.c"
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c
new file mode 100644 (file)
index 0000000..d26a1d1
--- /dev/null
@@ -0,0 +1,131 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+static int load_asic(struct echoaudio *chip);
+static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode);
+static int set_digital_mode(struct echoaudio *chip, u8 mode);
+static int check_asic_status(struct echoaudio *chip);
+static int set_sample_rate(struct echoaudio *chip, u32 rate);
+static int set_input_clock(struct echoaudio *chip, u16 clock);
+static int set_professional_spdif(struct echoaudio *chip, char prof);
+static int set_phantom_power(struct echoaudio *chip, char on);
+static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
+                            char force);
+
+#include <linux/irq.h>
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       local_irq_enable();
+       DE_INIT(("init_hw() - Echo3G\n"));
+       snd_assert((subdevice_id & 0xfff0) == ECHO3G, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->comm_page->e3g_frq_register =
+               __constant_cpu_to_le32((E3G_MAGIC_NUMBER / 48000) - 2);
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->has_midi = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_ECHO3G_DSP];
+
+       /* Load the DSP code and the ASIC on the PCI card and get
+       what type of external box is attached */
+       err = load_firmware(chip);
+
+       if (err < 0) {
+               return err;
+       } else if (err == E3G_GINA3G_BOX_TYPE) {
+               chip->input_clock_types =       ECHO_CLOCK_BIT_INTERNAL |
+                                               ECHO_CLOCK_BIT_SPDIF |
+                                               ECHO_CLOCK_BIT_ADAT;
+               chip->card_name = "Gina3G";
+               chip->px_digital_out = chip->bx_digital_out = 6;
+               chip->px_analog_in = chip->bx_analog_in = 14;
+               chip->px_digital_in = chip->bx_digital_in = 16;
+               chip->px_num = chip->bx_num = 24;
+               chip->has_phantom_power = TRUE;
+               chip->hasnt_input_nominal_level = TRUE;
+       } else if (err == E3G_LAYLA3G_BOX_TYPE) {
+               chip->input_clock_types =       ECHO_CLOCK_BIT_INTERNAL |
+                                               ECHO_CLOCK_BIT_SPDIF |
+                                               ECHO_CLOCK_BIT_ADAT |
+                                               ECHO_CLOCK_BIT_WORD;
+               chip->card_name = "Layla3G";
+               chip->px_digital_out = chip->bx_digital_out = 8;
+               chip->px_analog_in = chip->bx_analog_in = 16;
+               chip->px_digital_in = chip->bx_digital_in = 24;
+               chip->px_num = chip->bx_num = 32;
+       } else {
+               return -ENODEV;
+       }
+
+       chip->digital_modes =   ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
+                               ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
+                               ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
+       chip->digital_mode =    DIGITAL_MODE_SPDIF_RCA;
+       chip->professional_spdif = FALSE;
+       chip->non_audio_spdif = FALSE;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+       err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
+       snd_assert(err >= 0, return err);
+       err = set_phantom_power(chip, 0);
+       snd_assert(err >= 0, return err);
+       err = set_professional_spdif(chip, TRUE);
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static int set_phantom_power(struct echoaudio *chip, char on)
+{
+       u32 control_reg = le32_to_cpu(chip->comm_page->control_register);
+
+       if (on)
+               control_reg |= E3G_PHANTOM_POWER;
+       else
+               control_reg &= ~E3G_PHANTOM_POWER;
+
+       chip->phantom_power = on;
+       return write_control_reg(chip, control_reg,
+                                le32_to_cpu(chip->comm_page->e3g_frq_register),
+                                0);
+}
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
new file mode 100644 (file)
index 0000000..43b408a
--- /dev/null
@@ -0,0 +1,2196 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+MODULE_AUTHOR("Giuliano Pochini <pochini@shiny.it>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Echoaudio " ECHOCARD_NAME " soundcards driver");
+MODULE_SUPPORTED_DEVICE("{{Echoaudio," ECHOCARD_NAME "}}");
+MODULE_DEVICE_TABLE(pci, snd_echo_ids);
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " ECHOCARD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " ECHOCARD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
+
+static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
+
+static int get_firmware(const struct firmware **fw_entry,
+                       const struct firmware *frm, struct echoaudio *chip)
+{
+       int err;
+       char name[30];
+       DE_ACT(("firmware requested: %s\n", frm->data));
+       snprintf(name, sizeof(name), "ea/%s", frm->data);
+       if ((err = request_firmware(fw_entry, name, pci_device(chip))) < 0)
+               snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
+       return err;
+}
+
+static void free_firmware(const struct firmware *fw_entry)
+{
+       release_firmware(fw_entry);
+       DE_ACT(("firmware released\n"));
+}
+
+
+
+/******************************************************************************
+       PCM interface
+******************************************************************************/
+
+static void audiopipe_free(struct snd_pcm_runtime *runtime)
+{
+       struct audiopipe *pipe = runtime->private_data;
+
+       if (pipe->sgpage.area)
+               snd_dma_free_pages(&pipe->sgpage);
+       kfree(pipe);
+}
+
+
+
+static int hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params,
+                                             struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *c = hw_param_interval(params,
+                                                  SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_mask fmt;
+
+       snd_mask_any(&fmt);
+
+#ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+       /* >=2 channels cannot be S32_BE */
+       if (c->min == 2) {
+               fmt.bits[0] &= ~SNDRV_PCM_FMTBIT_S32_BE;
+               return snd_mask_refine(f, &fmt);
+       }
+#endif
+       /* > 2 channels cannot be U8 and S32_BE */
+       if (c->min > 2) {
+               fmt.bits[0] &= ~(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_BE);
+               return snd_mask_refine(f, &fmt);
+       }
+       /* Mono is ok with any format */
+       return 0;
+}
+
+
+
+static int hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params,
+                                             struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *c = hw_param_interval(params,
+                                                  SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_interval ch;
+
+       snd_interval_any(&ch);
+
+       /* S32_BE is mono (and stereo) only */
+       if (f->bits[0] == SNDRV_PCM_FMTBIT_S32_BE) {
+               ch.min = 1;
+#ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+               ch.max = 2;
+#else
+               ch.max = 1;
+#endif
+               ch.integer = 1;
+               return snd_interval_refine(c, &ch);
+       }
+       /* U8 can be only mono or stereo */
+       if (f->bits[0] == SNDRV_PCM_FMTBIT_U8) {
+               ch.min = 1;
+               ch.max = 2;
+               ch.integer = 1;
+               return snd_interval_refine(c, &ch);
+       }
+       /* S16_LE, S24_3LE and S32_LE support any number of channels. */
+       return 0;
+}
+
+
+
+static int hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params,
+                                              struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *c = hw_param_interval(params,
+                                                  SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_mask fmt;
+       u64 fmask;
+       snd_mask_any(&fmt);
+
+       fmask = fmt.bits[0] + ((u64)fmt.bits[1] << 32);
+
+       /* >2 channels must be S16_LE, S24_3LE or S32_LE */
+       if (c->min > 2) {
+               fmask &= SNDRV_PCM_FMTBIT_S16_LE |
+                        SNDRV_PCM_FMTBIT_S24_3LE |
+                        SNDRV_PCM_FMTBIT_S32_LE;
+       /* 1 channel must be S32_BE or S32_LE */
+       } else if (c->max == 1)
+               fmask &= SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE;
+#ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+       /* 2 channels cannot be S32_BE */
+       else if (c->min == 2 && c->max == 2)
+               fmask &= ~SNDRV_PCM_FMTBIT_S32_BE;
+#endif
+       else
+               return 0;
+
+       fmt.bits[0] &= (u32)fmask;
+       fmt.bits[1] &= (u32)(fmask >> 32);
+       return snd_mask_refine(f, &fmt);
+}
+
+
+
+static int hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,
+                                              struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *c = hw_param_interval(params,
+                                                  SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_interval ch;
+       u64 fmask;
+
+       snd_interval_any(&ch);
+       ch.integer = 1;
+       fmask = f->bits[0] + ((u64)f->bits[1] << 32);
+
+       /* S32_BE is mono (and stereo) only */
+       if (fmask == SNDRV_PCM_FMTBIT_S32_BE) {
+               ch.min = 1;
+#ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+               ch.max = 2;
+#else
+               ch.max = 1;
+#endif
+       /* U8 is stereo only */
+       } else if (fmask == SNDRV_PCM_FMTBIT_U8)
+               ch.min = ch.max = 2;
+       /* S16_LE and S24_3LE must be at least stereo */
+       else if (!(fmask & ~(SNDRV_PCM_FMTBIT_S16_LE |
+                              SNDRV_PCM_FMTBIT_S24_3LE)))
+               ch.min = 2;
+       else
+               return 0;
+
+       return snd_interval_refine(c, &ch);
+}
+
+
+
+/* Since the sample rate is a global setting, do allow the user to change the
+sample rate only if there is only one pcm device open. */
+static int hw_rule_sample_rate(struct snd_pcm_hw_params *params,
+                              struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                                                     SNDRV_PCM_HW_PARAM_RATE);
+       struct echoaudio *chip = rule->private;
+       struct snd_interval fixed;
+
+       if (!chip->can_set_rate) {
+               snd_interval_any(&fixed);
+               fixed.min = fixed.max = chip->sample_rate;
+               return snd_interval_refine(rate, &fixed);
+       }
+       return 0;
+}
+
+
+static int pcm_open(struct snd_pcm_substream *substream,
+                   signed char max_channels)
+{
+       struct echoaudio *chip;
+       struct snd_pcm_runtime *runtime;
+       struct audiopipe *pipe;
+       int err, i;
+
+       if (max_channels <= 0)
+               return -EAGAIN;
+
+       chip = snd_pcm_substream_chip(substream);
+       runtime = substream->runtime;
+
+       if (!(pipe = kmalloc(sizeof(struct audiopipe), GFP_KERNEL)))
+               return -ENOMEM;
+       memset(pipe, 0, sizeof(struct audiopipe));
+       pipe->index = -1;               /* Not configured yet */
+
+       /* Set up hw capabilities and contraints */
+       memcpy(&pipe->hw, &pcm_hardware_skel, sizeof(struct snd_pcm_hardware));
+       DE_HWP(("max_channels=%d\n", max_channels));
+       pipe->constr.list = channels_list;
+       pipe->constr.mask = 0;
+       for (i = 0; channels_list[i] <= max_channels; i++);
+       pipe->constr.count = i;
+       if (pipe->hw.channels_max > max_channels)
+               pipe->hw.channels_max = max_channels;
+       if (chip->digital_mode == DIGITAL_MODE_ADAT) {
+               pipe->hw.rate_max = 48000;
+               pipe->hw.rates &= SNDRV_PCM_RATE_8000_48000;
+       }
+
+       runtime->hw = pipe->hw;
+       runtime->private_data = pipe;
+       runtime->private_free = audiopipe_free;
+       snd_pcm_set_sync(substream);
+
+       /* Only mono and any even number of channels are allowed */
+       if ((err = snd_pcm_hw_constraint_list(runtime, 0,
+                                             SNDRV_PCM_HW_PARAM_CHANNELS,
+                                             &pipe->constr)) < 0)
+               return err;
+
+       /* All periods should have the same size */
+       if ((err = snd_pcm_hw_constraint_integer(runtime,
+                                                SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+               return err;
+
+       /* The hw accesses memory in chunks 32 frames long and they should be
+       32-bytes-aligned. It's not a requirement, but it seems that IRQs are
+       generated with a resolution of 32 frames. Thus we need the following */
+       if ((err = snd_pcm_hw_constraint_step(runtime, 0,
+                                             SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                             32)) < 0)
+               return err;
+       if ((err = snd_pcm_hw_constraint_step(runtime, 0,
+                                             SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                             32)) < 0)
+               return err;
+
+       if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                      SNDRV_PCM_HW_PARAM_RATE,
+                                       hw_rule_sample_rate, chip,
+                                      SNDRV_PCM_HW_PARAM_RATE, -1)) < 0)
+               return err;
+
+       /* Finally allocate a page for the scatter-gather list */
+       if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+                                      snd_dma_pci_data(chip->pci),
+                                      PAGE_SIZE, &pipe->sgpage)) < 0) {
+               DE_HWP(("s-g list allocation failed\n"));
+               return err;
+       }
+
+       return 0;
+}
+
+
+
+static int pcm_analog_in_open(struct snd_pcm_substream *substream)
+{
+       struct echoaudio *chip = snd_pcm_substream_chip(substream);
+       int err;
+
+       DE_ACT(("pcm_analog_in_open\n"));
+       if ((err = pcm_open(substream, num_analog_busses_in(chip) -
+                           substream->number)) < 0)
+               return err;
+       if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                      SNDRV_PCM_HW_PARAM_CHANNELS,
+                                      hw_rule_capture_channels_by_format, NULL,
+                                      SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
+               return err;
+       if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                      SNDRV_PCM_HW_PARAM_FORMAT,
+                                      hw_rule_capture_format_by_channels, NULL,
+                                      SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
+               return err;
+       atomic_inc(&chip->opencount);
+       if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
+               chip->can_set_rate=0;
+       DE_HWP(("pcm_analog_in_open  cs=%d  oc=%d  r=%d\n",
+               chip->can_set_rate, atomic_read(&chip->opencount),
+               chip->sample_rate));
+       return 0;
+}
+
+
+
+static int pcm_analog_out_open(struct snd_pcm_substream *substream)
+{
+       struct echoaudio *chip = snd_pcm_substream_chip(substream);
+       int max_channels, err;
+
+#ifdef ECHOCARD_HAS_VMIXER
+       max_channels = num_pipes_out(chip);
+#else
+       max_channels = num_analog_busses_out(chip);
+#endif
+       DE_ACT(("pcm_analog_out_open\n"));
+       if ((err = pcm_open(substream, max_channels - substream->number)) < 0)
+               return err;
+       if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                      SNDRV_PCM_HW_PARAM_CHANNELS,
+                                      hw_rule_playback_channels_by_format,
+                                      NULL,
+                                      SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
+               return err;
+       if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                      SNDRV_PCM_HW_PARAM_FORMAT,
+                                      hw_rule_playback_format_by_channels,
+                                      NULL,
+                                      SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
+               return err;
+       atomic_inc(&chip->opencount);
+       if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
+               chip->can_set_rate=0;
+       DE_HWP(("pcm_analog_out_open  cs=%d  oc=%d  r=%d\n",
+               chip->can_set_rate, atomic_read(&chip->opencount),
+               chip->sample_rate));
+       return 0;
+}
+
+
+
+#ifdef ECHOCARD_HAS_DIGITAL_IO
+
+static int pcm_digital_in_open(struct snd_pcm_substream *substream)
+{
+       struct echoaudio *chip = snd_pcm_substream_chip(substream);
+       int err, max_channels;
+
+       DE_ACT(("pcm_digital_in_open\n"));
+       max_channels = num_digital_busses_in(chip) - substream->number;
+       down(&chip->mode_mutex);
+       if (chip->digital_mode == DIGITAL_MODE_ADAT)
+               err = pcm_open(substream, max_channels);
+       else    /* If the card has ADAT, subtract the 6 channels
+                * that S/PDIF doesn't have
+                */
+               err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT);
+
+       if (err < 0)
+               goto din_exit;
+
+       if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                      SNDRV_PCM_HW_PARAM_CHANNELS,
+                                      hw_rule_capture_channels_by_format, NULL,
+                                      SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
+               goto din_exit;
+       if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                      SNDRV_PCM_HW_PARAM_FORMAT,
+                                      hw_rule_capture_format_by_channels, NULL,
+                                      SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
+               goto din_exit;
+
+       atomic_inc(&chip->opencount);
+       if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
+               chip->can_set_rate=0;
+
+din_exit:
+       up(&chip->mode_mutex);
+       return err;
+}
+
+
+
+#ifndef ECHOCARD_HAS_VMIXER    /* See the note in snd_echo_new_pcm() */
+
+static int pcm_digital_out_open(struct snd_pcm_substream *substream)
+{
+       struct echoaudio *chip = snd_pcm_substream_chip(substream);
+       int err, max_channels;
+
+       DE_ACT(("pcm_digital_out_open\n"));
+       max_channels = num_digital_busses_out(chip) - substream->number;
+       down(&chip->mode_mutex);
+       if (chip->digital_mode == DIGITAL_MODE_ADAT)
+               err = pcm_open(substream, max_channels);
+       else    /* If the card has ADAT, subtract the 6 channels
+                * that S/PDIF doesn't have
+                */
+               err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT);
+
+       if (err < 0)
+               goto dout_exit;
+
+       if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                      SNDRV_PCM_HW_PARAM_CHANNELS,
+                                      hw_rule_playback_channels_by_format,
+                                      NULL, SNDRV_PCM_HW_PARAM_FORMAT,
+                                      -1)) < 0)
+               goto dout_exit;
+       if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                      SNDRV_PCM_HW_PARAM_FORMAT,
+                                      hw_rule_playback_format_by_channels,
+                                      NULL, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                      -1)) < 0)
+               goto dout_exit;
+       atomic_inc(&chip->opencount);
+       if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
+               chip->can_set_rate=0;
+dout_exit:
+       up(&chip->mode_mutex);
+       return err;
+}
+
+#endif /* !ECHOCARD_HAS_VMIXER */
+
+#endif /* ECHOCARD_HAS_DIGITAL_IO */
+
+
+
+static int pcm_close(struct snd_pcm_substream *substream)
+{
+       struct echoaudio *chip = snd_pcm_substream_chip(substream);
+       int oc;
+
+       /* Nothing to do here. Audio is already off and pipe will be
+        * freed by its callback
+        */
+       DE_ACT(("pcm_close\n"));
+
+       atomic_dec(&chip->opencount);
+       oc = atomic_read(&chip->opencount);
+       DE_ACT(("pcm_close  oc=%d  cs=%d  rs=%d\n", oc,
+               chip->can_set_rate, chip->rate_set));
+       if (oc < 2)
+               chip->can_set_rate = 1;
+       if (oc == 0)
+               chip->rate_set = 0;
+       DE_ACT(("pcm_close2 oc=%d  cs=%d  rs=%d\n", oc,
+               chip->can_set_rate,chip->rate_set));
+
+       return 0;
+}
+
+
+
+/* Channel allocation and scatter-gather list setup */
+static int init_engine(struct snd_pcm_substream *substream,
+                      struct snd_pcm_hw_params *hw_params,
+                      int pipe_index, int interleave)
+{
+       struct echoaudio *chip;
+       int err, per, rest, page, edge, offs;
+       struct snd_sg_buf *sgbuf;
+       struct audiopipe *pipe;
+
+       chip = snd_pcm_substream_chip(substream);
+       pipe = (struct audiopipe *) substream->runtime->private_data;
+
+       /* Sets up che hardware. If it's already initialized, reset and
+        * redo with the new parameters
+        */
+       spin_lock_irq(&chip->lock);
+       if (pipe->index >= 0) {
+               DE_HWP(("hwp_ie free(%d)\n", pipe->index));
+               err = free_pipes(chip, pipe);
+               snd_assert(!err);
+               chip->substream[pipe->index] = NULL;
+       }
+
+       err = allocate_pipes(chip, pipe, pipe_index, interleave);
+       if (err < 0) {
+               spin_unlock_irq(&chip->lock);
+               DE_ACT((KERN_NOTICE "allocate_pipes(%d) err=%d\n",
+                       pipe_index, err));
+               return err;
+       }
+       spin_unlock_irq(&chip->lock);
+       DE_ACT((KERN_NOTICE "allocate_pipes()=%d\n", pipe_index));
+
+       DE_HWP(("pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n",
+               params_buffer_bytes(hw_params), params_periods(hw_params),
+               params_period_bytes(hw_params)));
+       err = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+       if (err < 0) {
+               snd_printk(KERN_ERR "malloc_pages err=%d\n", err);
+               spin_lock_irq(&chip->lock);
+               free_pipes(chip, pipe);
+               spin_unlock_irq(&chip->lock);
+               pipe->index = -1;
+               return err;
+       }
+
+       sgbuf = snd_pcm_substream_sgbuf(substream);
+
+       DE_HWP(("pcm_hw_params table size=%d pages=%d\n",
+               sgbuf->size, sgbuf->pages));
+       sglist_init(chip, pipe);
+       edge = PAGE_SIZE;
+       for (offs = page = per = 0; offs < params_buffer_bytes(hw_params);
+            per++) {
+               rest = params_period_bytes(hw_params);
+               if (offs + rest > params_buffer_bytes(hw_params))
+                       rest = params_buffer_bytes(hw_params) - offs;
+               while (rest) {
+                       if (rest <= edge - offs) {
+                               sglist_add_mapping(chip, pipe,
+                                                  snd_sgbuf_get_addr(sgbuf, offs),
+                                                  rest);
+                               sglist_add_irq(chip, pipe);
+                               offs += rest;
+                               rest = 0;
+                       } else {
+                               sglist_add_mapping(chip, pipe,
+                                                  snd_sgbuf_get_addr(sgbuf, offs),
+                                                  edge - offs);
+                               rest -= edge - offs;
+                               offs = edge;
+                       }
+                       if (offs == edge) {
+                               edge += PAGE_SIZE;
+                               page++;
+                       }
+               }
+       }
+
+       /* Close the ring buffer */
+       sglist_wrap(chip, pipe);
+
+       /* This stuff is used by the irq handler, so it must be
+        * initialized before chip->substream
+        */
+       chip->last_period[pipe_index] = 0;
+       pipe->last_counter = 0;
+       pipe->position = 0;
+       smp_wmb();
+       chip->substream[pipe_index] = substream;
+       chip->rate_set = 1;
+       spin_lock_irq(&chip->lock);
+       set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den);
+       spin_unlock_irq(&chip->lock);
+       DE_HWP(("pcm_hw_params ok\n"));
+       return 0;
+}
+
+
+
+static int pcm_analog_in_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *hw_params)
+{
+       struct echoaudio *chip = snd_pcm_substream_chip(substream);
+
+       return init_engine(substream, hw_params, px_analog_in(chip) +
+                       substream->number, params_channels(hw_params));
+}
+
+
+
+static int pcm_analog_out_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *hw_params)
+{
+       return init_engine(substream, hw_params, substream->number,
+                          params_channels(hw_params));
+}
+
+
+
+#ifdef ECHOCARD_HAS_DIGITAL_IO
+
+static int pcm_digital_in_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *hw_params)
+{
+       struct echoaudio *chip = snd_pcm_substream_chip(substream);
+
+       return init_engine(substream, hw_params, px_digital_in(chip) +
+                       substream->number, params_channels(hw_params));
+}
+
+
+
+#ifndef ECHOCARD_HAS_VMIXER    /* See the note in snd_echo_new_pcm() */
+static int pcm_digital_out_hw_params(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_hw_params *hw_params)
+{
+       struct echoaudio *chip = snd_pcm_substream_chip(substream);
+
+       return init_engine(substream, hw_params, px_digital_out(chip) +
+                       substream->number, params_channels(hw_params));
+}
+#endif /* !ECHOCARD_HAS_VMIXER */
+
+#endif /* ECHOCARD_HAS_DIGITAL_IO */
+
+
+
+static int pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct echoaudio *chip;
+       struct audiopipe *pipe;
+
+       chip = snd_pcm_substream_chip(substream);
+       pipe = (struct audiopipe *) substream->runtime->private_data;
+
+       spin_lock_irq(&chip->lock);
+       if (pipe->index >= 0) {
+               DE_HWP(("pcm_hw_free(%d)\n", pipe->index));
+               free_pipes(chip, pipe);
+               chip->substream[pipe->index] = NULL;
+               pipe->index = -1;
+       }
+       spin_unlock_irq(&chip->lock);
+
+       DE_HWP(("pcm_hw_freed\n"));
+       snd_pcm_lib_free_pages(substream);
+       return 0;
+}
+
+
+
+static int pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct echoaudio *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct audioformat format;
+       int pipe_index = ((struct audiopipe *)runtime->private_data)->index;
+
+       DE_HWP(("Prepare rate=%d format=%d channels=%d\n",
+               runtime->rate, runtime->format, runtime->channels));
+       format.interleave = runtime->channels;
+       format.data_are_bigendian = 0;
+       format.mono_to_stereo = 0;
+       switch (runtime->format) {
+       case SNDRV_PCM_FORMAT_U8:
+               format.bits_per_sample = 8;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               format.bits_per_sample = 16;
+               break;
+       case SNDRV_PCM_FORMAT_S24_3LE:
+               format.bits_per_sample = 24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_BE:
+               format.data_are_bigendian = 1;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               format.bits_per_sample = 32;
+               break;
+       default:
+               DE_HWP(("Prepare error: unsupported format %d\n",
+                       runtime->format));
+               return -EINVAL;
+       }
+
+       snd_assert(pipe_index < px_num(chip), return -EINVAL);
+       snd_assert(is_pipe_allocated(chip, pipe_index), return -EINVAL);
+       set_audio_format(chip, pipe_index, &format);
+       return 0;
+}
+
+
+
+static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct echoaudio *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct audiopipe *pipe = runtime->private_data;
+       int i, err;
+       u32 channelmask = 0;
+       struct list_head *pos;
+       struct snd_pcm_substream *s;
+
+       snd_pcm_group_for_each(pos, substream) {
+               s = snd_pcm_group_substream_entry(pos);
+               for (i = 0; i < DSP_MAXPIPES; i++) {
+                       if (s == chip->substream[i]) {
+                               channelmask |= 1 << i;
+                               snd_pcm_trigger_done(s, substream);
+                       }
+               }
+       }
+
+       spin_lock(&chip->lock);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               DE_ACT(("pcm_trigger start\n"));
+               for (i = 0; i < DSP_MAXPIPES; i++) {
+                       if (channelmask & (1 << i)) {
+                               pipe = chip->substream[i]->runtime->private_data;
+                               switch (pipe->state) {
+                               case PIPE_STATE_STOPPED:
+                                       chip->last_period[i] = 0;
+                                       pipe->last_counter = 0;
+                                       pipe->position = 0;
+                                       *pipe->dma_counter = 0;
+                               case PIPE_STATE_PAUSED:
+                                       pipe->state = PIPE_STATE_STARTED;
+                                       break;
+                               case PIPE_STATE_STARTED:
+                                       break;
+                               }
+                       }
+               }
+               err = start_transport(chip, channelmask,
+                                     chip->pipe_cyclic_mask);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               DE_ACT(("pcm_trigger stop\n"));
+               for (i = 0; i < DSP_MAXPIPES; i++) {
+                       if (channelmask & (1 << i)) {
+                               pipe = chip->substream[i]->runtime->private_data;
+                               pipe->state = PIPE_STATE_STOPPED;
+                       }
+               }
+               err = stop_transport(chip, channelmask);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               DE_ACT(("pcm_trigger pause\n"));
+               for (i = 0; i < DSP_MAXPIPES; i++) {
+                       if (channelmask & (1 << i)) {
+                               pipe = chip->substream[i]->runtime->private_data;
+                               pipe->state = PIPE_STATE_PAUSED;
+                       }
+               }
+               err = pause_transport(chip, channelmask);
+               break;
+       default:
+               err = -EINVAL;
+       }
+       spin_unlock(&chip->lock);
+       return err;
+}
+
+
+
+static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct audiopipe *pipe = runtime->private_data;
+       size_t cnt, bufsize, pos;
+
+       cnt = le32_to_cpu(*pipe->dma_counter);
+       pipe->position += cnt - pipe->last_counter;
+       pipe->last_counter = cnt;
+       bufsize = substream->runtime->buffer_size;
+       pos = bytes_to_frames(substream->runtime, pipe->position);
+
+       while (pos >= bufsize) {
+               pipe->position -= frames_to_bytes(substream->runtime, bufsize);
+               pos -= bufsize;
+       }
+       return pos;
+}
+
+
+
+/* pcm *_ops structures */
+static struct snd_pcm_ops analog_playback_ops = {
+       .open = pcm_analog_out_open,
+       .close = pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = pcm_analog_out_hw_params,
+       .hw_free = pcm_hw_free,
+       .prepare = pcm_prepare,
+       .trigger = pcm_trigger,
+       .pointer = pcm_pointer,
+       .page = snd_pcm_sgbuf_ops_page,
+};
+static struct snd_pcm_ops analog_capture_ops = {
+       .open = pcm_analog_in_open,
+       .close = pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = pcm_analog_in_hw_params,
+       .hw_free = pcm_hw_free,
+       .prepare = pcm_prepare,
+       .trigger = pcm_trigger,
+       .pointer = pcm_pointer,
+       .page = snd_pcm_sgbuf_ops_page,
+};
+#ifdef ECHOCARD_HAS_DIGITAL_IO
+#ifndef ECHOCARD_HAS_VMIXER
+static struct snd_pcm_ops digital_playback_ops = {
+       .open = pcm_digital_out_open,
+       .close = pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = pcm_digital_out_hw_params,
+       .hw_free = pcm_hw_free,
+       .prepare = pcm_prepare,
+       .trigger = pcm_trigger,
+       .pointer = pcm_pointer,
+       .page = snd_pcm_sgbuf_ops_page,
+};
+#endif /* !ECHOCARD_HAS_VMIXER */
+static struct snd_pcm_ops digital_capture_ops = {
+       .open = pcm_digital_in_open,
+       .close = pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = pcm_digital_in_hw_params,
+       .hw_free = pcm_hw_free,
+       .prepare = pcm_prepare,
+       .trigger = pcm_trigger,
+       .pointer = pcm_pointer,
+       .page = snd_pcm_sgbuf_ops_page,
+};
+#endif /* ECHOCARD_HAS_DIGITAL_IO */
+
+
+
+/* Preallocate memory only for the first substream because it's the most
+ * used one
+ */
+static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev)
+{
+       struct snd_pcm_substream *ss;
+       int stream, err;
+
+       for (stream = 0; stream < 2; stream++)
+               for (ss = pcm->streams[stream].substream; ss; ss = ss->next) {
+                       err = snd_pcm_lib_preallocate_pages(ss, SNDRV_DMA_TYPE_DEV_SG,
+                                                           dev,
+                                                           ss->number ? 0 : 128<<10,
+                                                           256<<10);
+                       if (err < 0)
+                               return err;
+               }
+       return 0;
+}
+
+
+
+/*<--snd_echo_probe() */
+static int __devinit snd_echo_new_pcm(struct echoaudio *chip)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+#ifdef ECHOCARD_HAS_VMIXER
+       /* This card has a Vmixer, that is there is no direct mapping from PCM
+       streams to physical outputs. The user can mix the streams as he wishes
+       via control interface and it's possible to send any stream to any
+       output, thus it makes no sense to keep analog and digital outputs
+       separated */
+
+       /* PCM#0 Virtual outputs and analog inputs */
+       if ((err = snd_pcm_new(chip->card, "PCM", 0, num_pipes_out(chip),
+                               num_analog_busses_in(chip), &pcm)) < 0)
+               return err;
+       pcm->private_data = chip;
+       chip->analog_pcm = pcm;
+       strcpy(pcm->name, chip->card->shortname);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
+       if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
+               return err;
+       DE_INIT(("Analog PCM ok\n"));
+
+#ifdef ECHOCARD_HAS_DIGITAL_IO
+       /* PCM#1 Digital inputs, no outputs */
+       if ((err = snd_pcm_new(chip->card, "Digital PCM", 1, 0,
+                              num_digital_busses_in(chip), &pcm)) < 0)
+               return err;
+       pcm->private_data = chip;
+       chip->digital_pcm = pcm;
+       strcpy(pcm->name, chip->card->shortname);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
+       if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
+               return err;
+       DE_INIT(("Digital PCM ok\n"));
+#endif /* ECHOCARD_HAS_DIGITAL_IO */
+
+#else /* ECHOCARD_HAS_VMIXER */
+
+       /* The card can manage substreams formed by analog and digital channels
+       at the same time, but I prefer to keep analog and digital channels
+       separated, because that mixed thing is confusing and useless. So we
+       register two PCM devices: */
+
+       /* PCM#0 Analog i/o */
+       if ((err = snd_pcm_new(chip->card, "Analog PCM", 0,
+                              num_analog_busses_out(chip),
+                              num_analog_busses_in(chip), &pcm)) < 0)
+               return err;
+       pcm->private_data = chip;
+       chip->analog_pcm = pcm;
+       strcpy(pcm->name, chip->card->shortname);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
+       if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
+               return err;
+       DE_INIT(("Analog PCM ok\n"));
+
+#ifdef ECHOCARD_HAS_DIGITAL_IO
+       /* PCM#1 Digital i/o */
+       if ((err = snd_pcm_new(chip->card, "Digital PCM", 1,
+                              num_digital_busses_out(chip),
+                              num_digital_busses_in(chip), &pcm)) < 0)
+               return err;
+       pcm->private_data = chip;
+       chip->digital_pcm = pcm;
+       strcpy(pcm->name, chip->card->shortname);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &digital_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
+       if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
+               return err;
+       DE_INIT(("Digital PCM ok\n"));
+#endif /* ECHOCARD_HAS_DIGITAL_IO */
+
+#endif /* ECHOCARD_HAS_VMIXER */
+
+       return 0;
+}
+
+
+
+
+/******************************************************************************
+       Control interface
+******************************************************************************/
+
+/******************* PCM output volume *******************/
+static int snd_echo_output_gain_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = num_busses_out(chip);
+       uinfo->value.integer.min = ECHOGAIN_MINOUT;
+       uinfo->value.integer.max = ECHOGAIN_MAXOUT;
+       return 0;
+}
+
+static int snd_echo_output_gain_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int c;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       for (c = 0; c < num_busses_out(chip); c++)
+               ucontrol->value.integer.value[c] = chip->output_gain[c];
+       return 0;
+}
+
+static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int c, changed, gain;
+
+       changed = 0;
+       chip = snd_kcontrol_chip(kcontrol);
+       spin_lock_irq(&chip->lock);
+       for (c = 0; c < num_busses_out(chip); c++) {
+               gain = ucontrol->value.integer.value[c];
+               /* Ignore out of range values */
+               if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
+                       continue;
+               if (chip->output_gain[c] != gain) {
+                       set_output_gain(chip, c, gain);
+                       changed = 1;
+               }
+       }
+       if (changed)
+               update_output_line_level(chip);
+       spin_unlock_irq(&chip->lock);
+       return changed;
+}
+
+#ifdef ECHOCARD_HAS_VMIXER
+/* On Vmixer cards this one controls the line-out volume */
+static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = {
+       .name = "Line Playback Volume",
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = snd_echo_output_gain_info,
+       .get = snd_echo_output_gain_get,
+       .put = snd_echo_output_gain_put,
+};
+#else
+static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
+       .name = "PCM Playback Volume",
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = snd_echo_output_gain_info,
+       .get = snd_echo_output_gain_get,
+       .put = snd_echo_output_gain_put,
+};
+#endif
+
+
+
+#ifdef ECHOCARD_HAS_INPUT_GAIN
+
+/******************* Analog input volume *******************/
+static int snd_echo_input_gain_info(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = num_analog_busses_in(chip);
+       uinfo->value.integer.min = ECHOGAIN_MININP;
+       uinfo->value.integer.max = ECHOGAIN_MAXINP;
+       return 0;
+}
+
+static int snd_echo_input_gain_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int c;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       for (c = 0; c < num_analog_busses_in(chip); c++)
+               ucontrol->value.integer.value[c] = chip->input_gain[c];
+       return 0;
+}
+
+static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int c, gain, changed;
+
+       changed = 0;
+       chip = snd_kcontrol_chip(kcontrol);
+       spin_lock_irq(&chip->lock);
+       for (c = 0; c < num_analog_busses_in(chip); c++) {
+               gain = ucontrol->value.integer.value[c];
+               /* Ignore out of range values */
+               if (gain < ECHOGAIN_MININP || gain > ECHOGAIN_MAXINP)
+                       continue;
+               if (chip->input_gain[c] != gain) {
+                       set_input_gain(chip, c, gain);
+                       changed = 1;
+               }
+       }
+       if (changed)
+               update_input_line_level(chip);
+       spin_unlock_irq(&chip->lock);
+       return changed;
+}
+
+static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = {
+       .name = "Line Capture Volume",
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = snd_echo_input_gain_info,
+       .get = snd_echo_input_gain_get,
+       .put = snd_echo_input_gain_put,
+};
+
+#endif /* ECHOCARD_HAS_INPUT_GAIN */
+
+
+
+#ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
+
+/************ Analog output nominal level (+4dBu / -10dBV) ***************/
+static int snd_echo_output_nominal_info (struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_info *uinfo)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = num_analog_busses_out(chip);
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int snd_echo_output_nominal_get(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int c;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       for (c = 0; c < num_analog_busses_out(chip); c++)
+               ucontrol->value.integer.value[c] = chip->nominal_level[c];
+       return 0;
+}
+
+static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int c, changed;
+
+       changed = 0;
+       chip = snd_kcontrol_chip(kcontrol);
+       spin_lock_irq(&chip->lock);
+       for (c = 0; c < num_analog_busses_out(chip); c++) {
+               if (chip->nominal_level[c] != ucontrol->value.integer.value[c]) {
+                       set_nominal_level(chip, c,
+                                         ucontrol->value.integer.value[c]);
+                       changed = 1;
+               }
+       }
+       if (changed)
+               update_output_line_level(chip);
+       spin_unlock_irq(&chip->lock);
+       return changed;
+}
+
+static struct snd_kcontrol_new snd_echo_output_nominal_level __devinitdata = {
+       .name = "Line Playback Switch (-10dBV)",
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = snd_echo_output_nominal_info,
+       .get = snd_echo_output_nominal_get,
+       .put = snd_echo_output_nominal_put,
+};
+
+#endif /* ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL */
+
+
+
+#ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
+
+/*************** Analog input nominal level (+4dBu / -10dBV) ***************/
+static int snd_echo_input_nominal_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = num_analog_busses_in(chip);
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int snd_echo_input_nominal_get(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int c;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       for (c = 0; c < num_analog_busses_in(chip); c++)
+               ucontrol->value.integer.value[c] =
+                       chip->nominal_level[bx_analog_in(chip) + c];
+       return 0;
+}
+
+static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int c, changed;
+
+       changed = 0;
+       chip = snd_kcontrol_chip(kcontrol);
+       spin_lock_irq(&chip->lock);
+       for (c = 0; c < num_analog_busses_in(chip); c++) {
+               if (chip->nominal_level[bx_analog_in(chip) + c] !=
+                   ucontrol->value.integer.value[c]) {
+                       set_nominal_level(chip, bx_analog_in(chip) + c,
+                                         ucontrol->value.integer.value[c]);
+                       changed = 1;
+               }
+       }
+       if (changed)
+               update_output_line_level(chip); /* "Output" is not a mistake
+                                                * here.
+                                                */
+       spin_unlock_irq(&chip->lock);
+       return changed;
+}
+
+static struct snd_kcontrol_new snd_echo_intput_nominal_level __devinitdata = {
+       .name = "Line Capture Switch (-10dBV)",
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = snd_echo_input_nominal_info,
+       .get = snd_echo_input_nominal_get,
+       .put = snd_echo_input_nominal_put,
+};
+
+#endif /* ECHOCARD_HAS_INPUT_NOMINAL_LEVEL */
+
+
+
+#ifdef ECHOCARD_HAS_MONITOR
+
+/******************* Monitor mixer *******************/
+static int snd_echo_mixer_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = ECHOGAIN_MINOUT;
+       uinfo->value.integer.max = ECHOGAIN_MAXOUT;
+       uinfo->dimen.d[0] = num_busses_out(chip);
+       uinfo->dimen.d[1] = num_busses_in(chip);
+       return 0;
+}
+
+static int snd_echo_mixer_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] =
+               chip->monitor_gain[ucontrol->id.index / num_busses_in(chip)]
+                       [ucontrol->id.index % num_busses_in(chip)];
+       return 0;
+}
+
+static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int changed,  gain;
+       short out, in;
+
+       changed = 0;
+       chip = snd_kcontrol_chip(kcontrol);
+       out = ucontrol->id.index / num_busses_in(chip);
+       in = ucontrol->id.index % num_busses_in(chip);
+       gain = ucontrol->value.integer.value[0];
+       if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
+               return -EINVAL;
+       if (chip->monitor_gain[out][in] != gain) {
+               spin_lock_irq(&chip->lock);
+               set_monitor_gain(chip, out, in, gain);
+               update_output_line_level(chip);
+               spin_unlock_irq(&chip->lock);
+               changed = 1;
+       }
+       return changed;
+}
+
+static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = {
+       .name = "Monitor Mixer Volume",
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = snd_echo_mixer_info,
+       .get = snd_echo_mixer_get,
+       .put = snd_echo_mixer_put,
+};
+
+#endif /* ECHOCARD_HAS_MONITOR */
+
+
+
+#ifdef ECHOCARD_HAS_VMIXER
+
+/******************* Vmixer *******************/
+static int snd_echo_vmixer_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = ECHOGAIN_MINOUT;
+       uinfo->value.integer.max = ECHOGAIN_MAXOUT;
+       uinfo->dimen.d[0] = num_busses_out(chip);
+       uinfo->dimen.d[1] = num_pipes_out(chip);
+       return 0;
+}
+
+static int snd_echo_vmixer_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] =
+               chip->vmixer_gain[ucontrol->id.index / num_pipes_out(chip)]
+                       [ucontrol->id.index % num_pipes_out(chip)];
+       return 0;
+}
+
+static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int gain, changed;
+       short vch, out;
+
+       changed = 0;
+       chip = snd_kcontrol_chip(kcontrol);
+       out = ucontrol->id.index / num_pipes_out(chip);
+       vch = ucontrol->id.index % num_pipes_out(chip);
+       gain = ucontrol->value.integer.value[0];
+       if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
+               return -EINVAL;
+       if (chip->vmixer_gain[out][vch] != ucontrol->value.integer.value[0]) {
+               spin_lock_irq(&chip->lock);
+               set_vmixer_gain(chip, out, vch, ucontrol->value.integer.value[0]);
+               update_vmixer_level(chip);
+               spin_unlock_irq(&chip->lock);
+               changed = 1;
+       }
+       return changed;
+}
+
+static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = {
+       .name = "VMixer Volume",
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = snd_echo_vmixer_info,
+       .get = snd_echo_vmixer_get,
+       .put = snd_echo_vmixer_put,
+};
+
+#endif /* ECHOCARD_HAS_VMIXER */
+
+
+
+#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH
+
+/******************* Digital mode switch *******************/
+static int snd_echo_digital_mode_info(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_info *uinfo)
+{
+       static char *names[4] = {
+               "S/PDIF Coaxial", "S/PDIF Optical", "ADAT Optical",
+               "S/PDIF Cdrom"
+       };
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->value.enumerated.items = chip->num_digital_modes;
+       uinfo->count = 1;
+       if (uinfo->value.enumerated.item >= chip->num_digital_modes)
+               uinfo->value.enumerated.item = chip->num_digital_modes - 1;
+       strcpy(uinfo->value.enumerated.name, names[
+                       chip->digital_mode_list[uinfo->value.enumerated.item]]);
+       return 0;
+}
+
+static int snd_echo_digital_mode_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int i, mode;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       mode = chip->digital_mode;
+       for (i = chip->num_digital_modes - 1; i >= 0; i--)
+               if (mode == chip->digital_mode_list[i]) {
+                       ucontrol->value.enumerated.item[0] = i;
+                       break;
+               }
+       return 0;
+}
+
+static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int changed;
+       unsigned short emode, dmode;
+
+       changed = 0;
+       chip = snd_kcontrol_chip(kcontrol);
+
+       emode = ucontrol->value.enumerated.item[0];
+       if (emode >= chip->num_digital_modes)
+               return -EINVAL;
+       dmode = chip->digital_mode_list[emode];
+
+       if (dmode != chip->digital_mode) {
+               /* mode_mutex is required to make this operation atomic wrt
+               pcm_digital_*_open() and set_input_clock() functions. */
+               down(&chip->mode_mutex);
+
+               /* Do not allow the user to change the digital mode when a pcm
+               device is open because it also changes the number of channels
+               and the allowed sample rates */
+               if (atomic_read(&chip->opencount)) {
+                       changed = -EAGAIN;
+               } else {
+                       changed = set_digital_mode(chip, dmode);
+                       /* If we had to change the clock source, report it */
+                       if (changed > 0 && chip->clock_src_ctl) {
+                               snd_ctl_notify(chip->card,
+                                              SNDRV_CTL_EVENT_MASK_VALUE,
+                                              &chip->clock_src_ctl->id);
+                               DE_ACT(("SDM() =%d\n", changed));
+                       }
+                       if (changed >= 0)
+                               changed = 1;    /* No errors */
+               }
+               up(&chip->mode_mutex);
+       }
+       return changed;
+}
+
+static struct snd_kcontrol_new snd_echo_digital_mode_switch __devinitdata = {
+       .name = "Digital mode Switch",
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .info = snd_echo_digital_mode_info,
+       .get = snd_echo_digital_mode_get,
+       .put = snd_echo_digital_mode_put,
+};
+
+#endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */
+
+
+
+#ifdef ECHOCARD_HAS_DIGITAL_IO
+
+/******************* S/PDIF mode switch *******************/
+static int snd_echo_spdif_mode_info(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       static char *names[2] = {"Consumer", "Professional"};
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->value.enumerated.items = 2;
+       uinfo->count = 1;
+       if (uinfo->value.enumerated.item)
+               uinfo->value.enumerated.item = 1;
+       strcpy(uinfo->value.enumerated.name,
+              names[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int snd_echo_spdif_mode_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.enumerated.item[0] = !!chip->professional_spdif;
+       return 0;
+}
+
+static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int mode;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       mode = !!ucontrol->value.enumerated.item[0];
+       if (mode != chip->professional_spdif) {
+               spin_lock_irq(&chip->lock);
+               set_professional_spdif(chip, mode);
+               spin_unlock_irq(&chip->lock);
+               return 1;
+       }
+       return 0;
+}
+
+static struct snd_kcontrol_new snd_echo_spdif_mode_switch __devinitdata = {
+       .name = "S/PDIF mode Switch",
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .info = snd_echo_spdif_mode_info,
+       .get = snd_echo_spdif_mode_get,
+       .put = snd_echo_spdif_mode_put,
+};
+
+#endif /* ECHOCARD_HAS_DIGITAL_IO */
+
+
+
+#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
+
+/******************* Select input clock source *******************/
+static int snd_echo_clock_source_info(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_info *uinfo)
+{
+       static char *names[8] = {
+               "Internal", "Word", "Super", "S/PDIF", "ADAT", "ESync",
+               "ESync96", "MTC"
+       };
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->value.enumerated.items = chip->num_clock_sources;
+       uinfo->count = 1;
+       if (uinfo->value.enumerated.item >= chip->num_clock_sources)
+               uinfo->value.enumerated.item = chip->num_clock_sources - 1;
+       strcpy(uinfo->value.enumerated.name, names[
+                       chip->clock_source_list[uinfo->value.enumerated.item]]);
+       return 0;
+}
+
+static int snd_echo_clock_source_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int i, clock;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       clock = chip->input_clock;
+
+       for (i = 0; i < chip->num_clock_sources; i++)
+               if (clock == chip->clock_source_list[i])
+                       ucontrol->value.enumerated.item[0] = i;
+
+       return 0;
+}
+
+static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int changed;
+       unsigned int eclock, dclock;
+
+       changed = 0;
+       chip = snd_kcontrol_chip(kcontrol);
+       eclock = ucontrol->value.enumerated.item[0];
+       if (eclock >= chip->input_clock_types)
+               return -EINVAL;
+       dclock = chip->clock_source_list[eclock];
+       if (chip->input_clock != dclock) {
+               down(&chip->mode_mutex);
+               spin_lock_irq(&chip->lock);
+               if ((changed = set_input_clock(chip, dclock)) == 0)
+                       changed = 1;    /* no errors */
+               spin_unlock_irq(&chip->lock);
+               up(&chip->mode_mutex);
+       }
+
+       if (changed < 0)
+               DE_ACT(("seticlk val%d err 0x%x\n", dclock, changed));
+
+       return changed;
+}
+
+static struct snd_kcontrol_new snd_echo_clock_source_switch __devinitdata = {
+       .name = "Sample Clock Source",
+       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+       .info = snd_echo_clock_source_info,
+       .get = snd_echo_clock_source_get,
+       .put = snd_echo_clock_source_put,
+};
+
+#endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */
+
+
+
+#ifdef ECHOCARD_HAS_PHANTOM_POWER
+
+/******************* Phantom power switch *******************/
+static int snd_echo_phantom_power_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int snd_echo_phantom_power_get(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = chip->phantom_power;
+       return 0;
+}
+
+static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
+       int power, changed = 0;
+
+       power = !!ucontrol->value.integer.value[0];
+       if (chip->phantom_power != power) {
+               spin_lock_irq(&chip->lock);
+               changed = set_phantom_power(chip, power);
+               spin_unlock_irq(&chip->lock);
+               if (changed == 0)
+                       changed = 1;    /* no errors */
+       }
+       return changed;
+}
+
+static struct snd_kcontrol_new snd_echo_phantom_power_switch __devinitdata = {
+       .name = "Phantom power Switch",
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .info = snd_echo_phantom_power_info,
+       .get = snd_echo_phantom_power_get,
+       .put = snd_echo_phantom_power_put,
+};
+
+#endif /* ECHOCARD_HAS_PHANTOM_POWER */
+
+
+
+#ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
+
+/******************* Digital input automute switch *******************/
+static int snd_echo_automute_info(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int snd_echo_automute_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = chip->digital_in_automute;
+       return 0;
+}
+
+static int snd_echo_automute_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
+       int automute, changed = 0;
+
+       automute = !!ucontrol->value.integer.value[0];
+       if (chip->digital_in_automute != automute) {
+               spin_lock_irq(&chip->lock);
+               changed = set_input_auto_mute(chip, automute);
+               spin_unlock_irq(&chip->lock);
+               if (changed == 0)
+                       changed = 1;    /* no errors */
+       }
+       return changed;
+}
+
+static struct snd_kcontrol_new snd_echo_automute_switch __devinitdata = {
+       .name = "Digital Capture Switch (automute)",
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .info = snd_echo_automute_info,
+       .get = snd_echo_automute_get,
+       .put = snd_echo_automute_put,
+};
+
+#endif /* ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE */
+
+
+
+/******************* VU-meters switch *******************/
+static int snd_echo_vumeters_switch_info(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_info *uinfo)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       spin_lock_irq(&chip->lock);
+       set_meters_on(chip, ucontrol->value.integer.value[0]);
+       spin_unlock_irq(&chip->lock);
+       return 1;
+}
+
+static struct snd_kcontrol_new snd_echo_vumeters_switch __devinitdata = {
+       .name = "VU-meters Switch",
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .access = SNDRV_CTL_ELEM_ACCESS_WRITE,
+       .info = snd_echo_vumeters_switch_info,
+       .put = snd_echo_vumeters_switch_put,
+};
+
+
+
+/***** Read VU-meters (input, output, analog and digital together) *****/
+static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_info *uinfo)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 96;
+       uinfo->value.integer.min = ECHOGAIN_MINOUT;
+       uinfo->value.integer.max = 0;
+#ifdef ECHOCARD_HAS_VMIXER
+       uinfo->dimen.d[0] = 3;  /* Out, In, Virt */
+#else
+       uinfo->dimen.d[0] = 2;  /* Out, In */
+#endif
+       uinfo->dimen.d[1] = 16; /* 16 channels */
+       uinfo->dimen.d[2] = 2;  /* 0=level, 1=peak */
+       return 0;
+}
+
+static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       get_audio_meters(chip, ucontrol->value.integer.value);
+       return 0;
+}
+
+static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = {
+       .name = "VU-meters",
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info = snd_echo_vumeters_info,
+       .get = snd_echo_vumeters_get,
+};
+
+
+
+/*** Channels info - it exports informations about the number of channels ***/
+static int snd_echo_channels_info_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       struct echoaudio *chip;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 6;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1 << ECHO_CLOCK_NUMBER;
+       return 0;
+}
+
+static int snd_echo_channels_info_get(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct echoaudio *chip;
+       int detected, clocks, bit, src;
+
+       chip = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] = num_busses_in(chip);
+       ucontrol->value.integer.value[1] = num_analog_busses_in(chip);
+       ucontrol->value.integer.value[2] = num_busses_out(chip);
+       ucontrol->value.integer.value[3] = num_analog_busses_out(chip);
+       ucontrol->value.integer.value[4] = num_pipes_out(chip);
+
+       /* Compute the bitmask of the currently valid input clocks */
+       detected = detect_input_clocks(chip);
+       clocks = 0;
+       src = chip->num_clock_sources - 1;
+       for (bit = ECHO_CLOCK_NUMBER - 1; bit >= 0; bit--)
+               if (detected & (1 << bit))
+                       for (; src >= 0; src--)
+                               if (bit == chip->clock_source_list[src]) {
+                                       clocks |= 1 << src;
+                                       break;
+                               }
+       ucontrol->value.integer.value[5] = clocks;
+
+       return 0;
+}
+
+static struct snd_kcontrol_new snd_echo_channels_info __devinitdata = {
+       .name = "Channels info",
+       .iface = SNDRV_CTL_ELEM_IFACE_HWDEP,
+       .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+       .info = snd_echo_channels_info_info,
+       .get = snd_echo_channels_info_get,
+};
+
+
+
+
+/******************************************************************************
+       IRQ Handler
+******************************************************************************/
+
+static irqreturn_t snd_echo_interrupt(int irq, void *dev_id,
+                                     struct pt_regs *regs)
+{
+       struct echoaudio *chip = dev_id;
+       struct snd_pcm_substream *substream;
+       int period, ss, st;
+
+       spin_lock(&chip->lock);
+       st = service_irq(chip);
+       if (st < 0) {
+               spin_unlock(&chip->lock);
+               return IRQ_NONE;
+       }
+       /* The hardware doesn't tell us which substream caused the irq,
+       thus we have to check all running substreams. */
+       for (ss = 0; ss < DSP_MAXPIPES; ss++) {
+               if ((substream = chip->substream[ss])) {
+                       period = pcm_pointer(substream) /
+                               substream->runtime->period_size;
+                       if (period != chip->last_period[ss]) {
+                               chip->last_period[ss] = period;
+                               spin_unlock(&chip->lock);
+                               snd_pcm_period_elapsed(substream);
+                               spin_lock(&chip->lock);
+                       }
+               }
+       }
+       spin_unlock(&chip->lock);
+
+#ifdef ECHOCARD_HAS_MIDI
+       if (st > 0 && chip->midi_in) {
+               snd_rawmidi_receive(chip->midi_in, chip->midi_buffer, st);
+               DE_MID(("rawmidi_iread=%d\n", st));
+       }
+#endif
+       return IRQ_HANDLED;
+}
+
+
+
+
+/******************************************************************************
+       Module construction / destruction
+******************************************************************************/
+
+static int snd_echo_free(struct echoaudio *chip)
+{
+       DE_INIT(("Stop DSP...\n"));
+       if (chip->comm_page) {
+               rest_in_peace(chip);
+               snd_dma_free_pages(&chip->commpage_dma_buf);
+       }
+       DE_INIT(("Stopped.\n"));
+
+       if (chip->irq >= 0)
+               free_irq(chip->irq, (void *)chip);
+
+       if (chip->dsp_registers)
+               iounmap(chip->dsp_registers);
+
+       if (chip->iores)
+               release_and_free_resource(chip->iores);
+
+       DE_INIT(("MMIO freed.\n"));
+
+       pci_disable_device(chip->pci);
+
+       /* release chip data */
+       kfree(chip);
+       DE_INIT(("Chip freed.\n"));
+       return 0;
+}
+
+
+
+static int snd_echo_dev_free(struct snd_device *device)
+{
+       struct echoaudio *chip = device->device_data;
+
+       DE_INIT(("snd_echo_dev_free()...\n"));
+       return snd_echo_free(chip);
+}
+
+
+
+/* <--snd_echo_probe() */
+static __devinit int snd_echo_create(struct snd_card *card,
+                                    struct pci_dev *pci,
+                                    struct echoaudio **rchip)
+{
+       struct echoaudio *chip;
+       int err;
+       size_t sz;
+       static struct snd_device_ops ops = {
+               .dev_free = snd_echo_dev_free,
+       };
+
+       *rchip = NULL;
+
+       pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0xC0);
+
+       if ((err = pci_enable_device(pci)) < 0)
+               return err;
+       pci_set_master(pci);
+
+       /* allocate a chip-specific data */
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip) {
+               pci_disable_device(pci);
+               return -ENOMEM;
+       }
+       DE_INIT(("chip=%p\n", chip));
+
+       spin_lock_init(&chip->lock);
+       chip->card = card;
+       chip->pci = pci;
+       chip->irq = -1;
+
+       /* PCI resource allocation */
+       chip->dsp_registers_phys = pci_resource_start(pci, 0);
+       sz = pci_resource_len(pci, 0);
+       if (sz > PAGE_SIZE)
+               sz = PAGE_SIZE;         /* We map only the required part */
+
+       if ((chip->iores = request_mem_region(chip->dsp_registers_phys, sz,
+                                             ECHOCARD_NAME)) == NULL) {
+               snd_echo_free(chip);
+               snd_printk(KERN_ERR "cannot get memory region\n");
+               return -EBUSY;
+       }
+       chip->dsp_registers = (volatile u32 __iomem *)
+               ioremap_nocache(chip->dsp_registers_phys, sz);
+
+       if (request_irq(pci->irq, snd_echo_interrupt, SA_INTERRUPT | SA_SHIRQ,
+                                               ECHOCARD_NAME, (void *)chip)) {
+               snd_echo_free(chip);
+               snd_printk(KERN_ERR "cannot grab irq\n");
+               return -EBUSY;
+       }
+       chip->irq = pci->irq;
+       DE_INIT(("pci=%p irq=%d subdev=%04x Init hardware...\n",
+                chip->pci, chip->irq, chip->pci->subsystem_device));
+
+       /* Create the DSP comm page - this is the area of memory used for most
+       of the communication with the DSP, which accesses it via bus mastering */
+       if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+                               sizeof(struct comm_page),
+                               &chip->commpage_dma_buf) < 0) {
+               snd_echo_free(chip);
+               snd_printk(KERN_ERR "cannot allocate the comm page\n");
+               return -ENOMEM;
+       }
+       chip->comm_page_phys = chip->commpage_dma_buf.addr;
+       chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area;
+
+       err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
+       if (err) {
+               DE_INIT(("init_hw err=%d\n", err));
+               snd_echo_free(chip);
+               return err;
+       }
+       DE_INIT(("Card init OK\n"));
+
+       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+               snd_echo_free(chip);
+               return err;
+       }
+       atomic_set(&chip->opencount, 0);
+       init_MUTEX(&chip->mode_mutex);
+       chip->can_set_rate = 1;
+       *rchip = chip;
+       /* Init done ! */
+       return 0;
+}
+
+
+
+/* constructor */
+static int __devinit snd_echo_probe(struct pci_dev *pci,
+                                   const struct pci_device_id *pci_id)
+{
+       static int dev;
+       struct snd_card *card;
+       struct echoaudio *chip;
+       char *dsp;
+       int i, err;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+
+       DE_INIT(("Echoaudio driver starting...\n"));
+       i = 0;
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+       if (card == NULL)
+               return -ENOMEM;
+
+       if ((err = snd_echo_create(card, pci, &chip)) < 0) {
+               snd_card_free(card);
+               return err;
+       }
+
+       strcpy(card->driver, "Echo_" ECHOCARD_NAME);
+       strcpy(card->shortname, chip->card_name);
+
+       dsp = "56301";
+       if (pci_id->device == 0x3410)
+               dsp = "56361";
+
+       sprintf(card->longname, "%s rev.%d (DSP%s) at 0x%lx irq %i",
+               card->shortname, pci_id->subdevice & 0x000f, dsp,
+               chip->dsp_registers_phys, chip->irq);
+
+       if ((err = snd_echo_new_pcm(chip)) < 0) {
+               snd_printk(KERN_ERR "new pcm error %d\n", err);
+               snd_card_free(card);
+               return err;
+       }
+
+#ifdef ECHOCARD_HAS_MIDI
+       if (chip->has_midi) {   /* Some Mia's do not have midi */
+               if ((err = snd_echo_midi_create(card, chip)) < 0) {
+                       snd_printk(KERN_ERR "new midi error %d\n", err);
+                       snd_card_free(card);
+                       return err;
+               }
+       }
+#endif
+
+#ifdef ECHOCARD_HAS_VMIXER
+       snd_echo_vmixer.count = num_pipes_out(chip) * num_busses_out(chip);
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_output_gain, chip))) < 0)
+               goto ctl_error;
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip))) < 0)
+               goto ctl_error;
+#else
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_pcm_output_gain, chip))) < 0)
+               goto ctl_error;
+#endif
+
+#ifdef ECHOCARD_HAS_INPUT_GAIN
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_input_gain, chip))) < 0)
+               goto ctl_error;
+#endif
+
+#ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
+       if (!chip->hasnt_input_nominal_level)
+               if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_intput_nominal_level, chip))) < 0)
+                       goto ctl_error;
+#endif
+
+#ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_output_nominal_level, chip))) < 0)
+               goto ctl_error;
+#endif
+
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters_switch, chip))) < 0)
+               goto ctl_error;
+
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters, chip))) < 0)
+               goto ctl_error;
+
+#ifdef ECHOCARD_HAS_MONITOR
+       snd_echo_monitor_mixer.count = num_busses_in(chip) * num_busses_out(chip);
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_monitor_mixer, chip))) < 0)
+               goto ctl_error;
+#endif
+
+#ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_automute_switch, chip))) < 0)
+               goto ctl_error;
+#endif
+
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_channels_info, chip))) < 0)
+               goto ctl_error;
+
+#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH
+       /* Creates a list of available digital modes */
+       chip->num_digital_modes = 0;
+       for (i = 0; i < 6; i++)
+               if (chip->digital_modes & (1 << i))
+                       chip->digital_mode_list[chip->num_digital_modes++] = i;
+
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_digital_mode_switch, chip))) < 0)
+               goto ctl_error;
+#endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */
+
+#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
+       /* Creates a list of available clock sources */
+       chip->num_clock_sources = 0;
+       for (i = 0; i < 10; i++)
+               if (chip->input_clock_types & (1 << i))
+                       chip->clock_source_list[chip->num_clock_sources++] = i;
+
+       if (chip->num_clock_sources > 1) {
+               chip->clock_src_ctl = snd_ctl_new1(&snd_echo_clock_source_switch, chip);
+               if ((err = snd_ctl_add(chip->card, chip->clock_src_ctl)) < 0)
+                       goto ctl_error;
+       }
+#endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */
+
+#ifdef ECHOCARD_HAS_DIGITAL_IO
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_spdif_mode_switch, chip))) < 0)
+               goto ctl_error;
+#endif
+
+#ifdef ECHOCARD_HAS_PHANTOM_POWER
+       if (chip->has_phantom_power)
+               if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_phantom_power_switch, chip))) < 0)
+                       goto ctl_error;
+#endif
+
+       if ((err = snd_card_register(card)) < 0) {
+               snd_card_free(card);
+               goto ctl_error;
+       }
+       snd_printk(KERN_INFO "Card registered: %s\n", card->longname);
+
+       pci_set_drvdata(pci, chip);
+       dev++;
+       return 0;
+
+ctl_error:
+       snd_printk(KERN_ERR "new control error %d\n", err);
+       snd_card_free(card);
+       return err;
+}
+
+
+
+static void __devexit snd_echo_remove(struct pci_dev *pci)
+{
+       struct echoaudio *chip;
+
+       chip = pci_get_drvdata(pci);
+       if (chip)
+               snd_card_free(chip->card);
+       pci_set_drvdata(pci, NULL);
+}
+
+
+
+/******************************************************************************
+       Everything starts and ends here
+******************************************************************************/
+
+/* pci_driver definition */
+static struct pci_driver driver = {
+       .name = "Echoaudio " ECHOCARD_NAME,
+       .id_table = snd_echo_ids,
+       .probe = snd_echo_probe,
+       .remove = __devexit_p(snd_echo_remove),
+};
+
+
+
+/* initialization of the module */
+static int __init alsa_card_echo_init(void)
+{
+       return pci_register_driver(&driver);
+}
+
+
+
+/* clean up the module */
+static void __exit alsa_card_echo_exit(void)
+{
+       pci_unregister_driver(&driver);
+}
+
+
+module_init(alsa_card_echo_init)
+module_exit(alsa_card_echo_exit)
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h
new file mode 100644 (file)
index 0000000..7e88c96
--- /dev/null
@@ -0,0 +1,590 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+ ****************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+ ****************************************************************************
+
+
+   Here's a block diagram of how most of the cards work:
+
+                  +-----------+
+           record |           |<-------------------- Inputs
+          <-------|           |        |
+     PCI          | Transport |        |
+     bus          |  engine   |       \|/
+          ------->|           |    +-------+
+            play  |           |--->|monitor|-------> Outputs
+                  +-----------+    | mixer |
+                                   +-------+
+
+   The lines going to and from the PCI bus represent "pipes".  A pipe performs
+   audio transport - moving audio data to and from buffers on the host via
+   bus mastering.
+
+   The inputs and outputs on the right represent input and output "busses."
+   A bus is a physical, real connection to the outside world.  An example
+   of a bus would be the 1/4" analog connectors on the back of Layla or
+   an RCA S/PDIF connector.
+
+   For most cards, there is a one-to-one correspondence between outputs
+   and busses; that is, each individual pipe is hard-wired to a single bus.
+
+   Cards that work this way are Darla20, Gina20, Layla20, Darla24, Gina24,
+   Layla24, Mona, and Indigo.
+
+
+   Mia has a feature called "virtual outputs."
+
+
+                  +-----------+
+           record |           |<----------------------------- Inputs
+          <-------|           |                  |
+     PCI          | Transport |                  |
+     bus          |  engine   |                 \|/
+          ------->|           |   +------+   +-------+
+            play  |           |-->|vmixer|-->|monitor|-------> Outputs
+                  +-----------+   +------+   | mixer |
+                                             +-------+
+
+
+   Obviously, the difference here is the box labeled "vmixer."  Vmixer is
+   short for "virtual output mixer."  For Mia, pipes are *not* hard-wired
+   to a single bus; the vmixer lets you mix any pipe to any bus in any
+   combination.
+
+   Note, however, that the left-hand side of the diagram is unchanged.
+   Transport works exactly the same way - the difference is in the mixer stage.
+
+
+   Pipes and busses are numbered starting at zero.
+
+
+
+   Pipe index
+   ==========
+
+   A number of calls in CEchoGals refer to a "pipe index".  A pipe index is
+   a unique number for a pipe that unambiguously refers to a playback or record
+   pipe.  Pipe indices are numbered starting with analog outputs, followed by
+   digital outputs, then analog inputs, then digital inputs.
+
+   Take Gina24 as an example:
+
+   Pipe index
+
+   0-7            Analog outputs (0 .. FirstDigitalBusOut-1)
+   8-15           Digital outputs (FirstDigitalBusOut .. NumBussesOut-1)
+   16-17          Analog inputs
+   18-25          Digital inputs
+
+
+   You get the pipe index by calling CEchoGals::OpenAudio; the other transport
+   functions take the pipe index as a parameter.  If you need a pipe index for
+   some other reason, use the handy Makepipe_index method.
+
+
+   Some calls take a CChannelMask parameter; CChannelMask is a handy way to
+   group pipe indices.
+
+
+
+   Digital mode switch
+   ===================
+
+   Some cards (right now, Gina24, Layla24, and Mona) have a Digital Mode Switch
+   or DMS.  Cards with a DMS can be set to one of three mutually exclusive
+   digital modes: S/PDIF RCA, S/PDIF optical, or ADAT optical.
+
+   This may create some confusion since ADAT optical is 8 channels wide and
+   S/PDIF is only two channels wide.  Gina24, Layla24, and Mona handle this
+   by acting as if they always have 8 digital outs and ins.  If you are in
+   either S/PDIF mode, the last 6 channels don't do anything - data sent
+   out these channels is thrown away and you will always record zeros.
+
+   Note that with Gina24, Layla24, and Mona, sample rates above 50 kHz are
+   only available if you have the card configured for S/PDIF optical or S/PDIF
+   RCA.
+
+
+
+   Double speed mode
+   =================
+
+   Some of the cards support 88.2 kHz and 96 kHz sampling (Darla24, Gina24,
+   Layla24, Mona, Mia, and Indigo).  For these cards, the driver sometimes has
+   to worry about "double speed mode"; double speed mode applies whenever the
+   sampling rate is above 50 kHz.
+
+   For instance, Mona and Layla24 support word clock sync.  However, they
+   actually support two different word clock modes - single speed (below
+   50 kHz) and double speed (above 50 kHz).  The hardware detects if a single
+   or double speed word clock signal is present; the generic code uses that
+   information to determine which mode to use.
+
+   The generic code takes care of all this for you.
+*/
+
+
+#ifndef _ECHOAUDIO_H_
+#define _ECHOAUDIO_H_
+
+
+#define TRUE 1
+#define FALSE 0
+
+#include "echoaudio_dsp.h"
+
+
+
+/***********************************************************************
+
+       PCI configuration space
+
+***********************************************************************/
+
+/*
+ * PCI vendor ID and device IDs for the hardware
+ */
+#define VENDOR_ID              0x1057
+#define DEVICE_ID_56301                0x1801
+#define DEVICE_ID_56361                0x3410
+#define SUBVENDOR_ID           0xECC0
+
+
+/*
+ * Valid Echo PCI subsystem card IDs
+ */
+#define DARLA20                        0x0010
+#define GINA20                 0x0020
+#define LAYLA20                        0x0030
+#define DARLA24                        0x0040
+#define GINA24                 0x0050
+#define LAYLA24                        0x0060
+#define MONA                   0x0070
+#define MIA                    0x0080
+#define INDIGO                 0x0090
+#define INDIGO_IO              0x00a0
+#define INDIGO_DJ              0x00b0
+#define ECHO3G                 0x0100
+
+
+/************************************************************************
+
+       Array sizes and so forth
+
+***********************************************************************/
+
+/*
+ * Sizes
+ */
+#define ECHO_MAXAUDIOINPUTS    32      /* Max audio input channels */
+#define ECHO_MAXAUDIOOUTPUTS   32      /* Max audio output channels */
+#define ECHO_MAXAUDIOPIPES     32      /* Max number of input and output
+                                        * pipes */
+#define E3G_MAX_OUTPUTS                16
+#define ECHO_MAXMIDIJACKS      1       /* Max MIDI ports */
+#define ECHO_MIDI_QUEUE_SZ     512     /* Max MIDI input queue entries */
+#define ECHO_MTC_QUEUE_SZ      32      /* Max MIDI time code input queue
+                                        * entries */
+
+/*
+ * MIDI activity indicator timeout
+ */
+#define MIDI_ACTIVITY_TIMEOUT_USEC     200000
+
+
+/****************************************************************************
+   Clocks
+
+*****************************************************************************/
+
+/*
+ * Clock numbers
+ */
+#define ECHO_CLOCK_INTERNAL            0
+#define ECHO_CLOCK_WORD                        1
+#define ECHO_CLOCK_SUPER               2
+#define ECHO_CLOCK_SPDIF               3
+#define ECHO_CLOCK_ADAT                        4
+#define ECHO_CLOCK_ESYNC               5
+#define ECHO_CLOCK_ESYNC96             6
+#define ECHO_CLOCK_MTC                 7
+#define ECHO_CLOCK_NUMBER              8
+#define ECHO_CLOCKS                    0xffff
+
+/*
+ * Clock bit numbers - used to report capabilities and whatever clocks
+ * are being detected dynamically.
+ */
+#define ECHO_CLOCK_BIT_INTERNAL                (1 << ECHO_CLOCK_INTERNAL)
+#define ECHO_CLOCK_BIT_WORD            (1 << ECHO_CLOCK_WORD)
+#define ECHO_CLOCK_BIT_SUPER           (1 << ECHO_CLOCK_SUPER)
+#define ECHO_CLOCK_BIT_SPDIF           (1 << ECHO_CLOCK_SPDIF)
+#define ECHO_CLOCK_BIT_ADAT            (1 << ECHO_CLOCK_ADAT)
+#define ECHO_CLOCK_BIT_ESYNC           (1 << ECHO_CLOCK_ESYNC)
+#define ECHO_CLOCK_BIT_ESYNC96         (1 << ECHO_CLOCK_ESYNC96)
+#define ECHO_CLOCK_BIT_MTC             (1<<ECHO_CLOCK_MTC)
+
+
+/***************************************************************************
+
+   Digital modes
+
+****************************************************************************/
+
+/*
+ * Digital modes for Mona, Layla24, and Gina24
+ */
+#define DIGITAL_MODE_NONE                      0xFF
+#define DIGITAL_MODE_SPDIF_RCA                 0
+#define DIGITAL_MODE_SPDIF_OPTICAL             1
+#define DIGITAL_MODE_ADAT                      2
+#define DIGITAL_MODE_SPDIF_CDROM               3
+#define DIGITAL_MODES                          4
+
+/*
+ * Digital mode capability masks
+ */
+#define ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA    (1 << DIGITAL_MODE_SPDIF_RCA)
+#define ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL        (1 << DIGITAL_MODE_SPDIF_OPTICAL)
+#define ECHOCAPS_HAS_DIGITAL_MODE_ADAT         (1 << DIGITAL_MODE_ADAT)
+#define ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_CDROM  (1 << DIGITAL_MODE_SPDIF_CDROM)
+
+
+#define EXT_3GBOX_NC                   0x01    /* 3G box not connected */
+#define EXT_3GBOX_NOT_SET              0x02    /* 3G box not detected yet */
+
+
+#define ECHOGAIN_MUTED         (-128)  /* Minimum possible gain */
+#define ECHOGAIN_MINOUT                (-128)  /* Min output gain (dB) */
+#define ECHOGAIN_MAXOUT                (6)     /* Max output gain (dB) */
+#define ECHOGAIN_MININP                (-50)   /* Min input gain (0.5 dB) */
+#define ECHOGAIN_MAXINP                (50)    /* Max input gain (0.5 dB) */
+
+#define PIPE_STATE_STOPPED     0       /* Pipe has been reset */
+#define PIPE_STATE_PAUSED      1       /* Pipe has been stopped */
+#define PIPE_STATE_STARTED     2       /* Pipe has been started */
+#define PIPE_STATE_PENDING     3       /* Pipe has pending start */
+
+
+/* Debug initialization */
+#ifdef CONFIG_SND_DEBUG
+#define DE_INIT(x) snd_printk x
+#else
+#define DE_INIT(x)
+#endif
+
+/* Debug hw_params callbacks */
+#ifdef CONFIG_SND_DEBUG
+#define DE_HWP(x) snd_printk x
+#else
+#define DE_HWP(x)
+#endif
+
+/* Debug normal activity (open, start, stop...) */
+#ifdef CONFIG_SND_DEBUG
+#define DE_ACT(x) snd_printk x
+#else
+#define DE_ACT(x)
+#endif
+
+/* Debug midi activity */
+#ifdef CONFIG_SND_DEBUG
+#define DE_MID(x) snd_printk x
+#else
+#define DE_MID(x)
+#endif
+
+
+struct audiopipe {
+       volatile u32 *dma_counter;      /* Commpage register that contains
+                                        * the current dma position
+                                        * (lower 32 bits only)
+                                        */
+       u32 last_counter;               /* The last position, which is used
+                                        * to compute...
+                                        */
+       u32 position;                   /* ...the number of bytes tranferred
+                                        * by the DMA engine, modulo the
+                                        * buffer size
+                                        */
+       short index;                    /* Index of the first channel or <0
+                                        * if hw is not configured yet
+                                        */
+       short interleave;
+       struct snd_dma_buffer sgpage;   /* Room for the scatter-gather list */
+       struct snd_pcm_hardware hw;
+       struct snd_pcm_hw_constraint_list constr;
+       short sglist_head;
+       char state;                     /* pipe state */
+};
+
+
+struct audioformat {
+       u8 interleave;                  /* How the data is arranged in memory:
+                                        * mono = 1, stereo = 2, ...
+                                        */
+       u8 bits_per_sample;             /* 8, 16, 24, 32 (24 bits left aligned) */
+       char mono_to_stereo;            /* Only used if interleave is 1 and
+                                        * if this is an output pipe.
+                                        */
+       char data_are_bigendian;        /* 1 = big endian, 0 = little endian */
+};
+
+
+struct echoaudio {
+       spinlock_t lock;
+       struct snd_pcm_substream *substream[DSP_MAXPIPES];
+       int last_period[DSP_MAXPIPES];
+       struct semaphore mode_mutex;
+       u16 num_digital_modes, digital_mode_list[6];
+       u16 num_clock_sources, clock_source_list[10];
+       atomic_t opencount;
+       struct snd_kcontrol *clock_src_ctl;
+       struct snd_pcm *analog_pcm, *digital_pcm;
+       struct snd_card *card;
+       const char *card_name;
+       struct pci_dev *pci;
+       unsigned long dsp_registers_phys;
+       struct resource *iores;
+       struct snd_dma_buffer commpage_dma_buf;
+       int irq;
+#ifdef ECHOCARD_HAS_MIDI
+       struct snd_rawmidi *rmidi;
+       struct snd_rawmidi_substream *midi_in, *midi_out;
+#endif
+       struct timer_list timer;
+       char tinuse;                            /* Timer in use */
+       char midi_full;                         /* MIDI output buffer is full */
+       char can_set_rate;
+       char rate_set;
+
+       /* This stuff is used mainly by the lowlevel code */
+       struct comm_page *comm_page;    /* Virtual address of the memory
+                                        * seen by DSP
+                                        */
+       u32 pipe_alloc_mask;            /* Bitmask of allocated pipes */
+       u32 pipe_cyclic_mask;           /* Bitmask of pipes with cyclic
+                                        * buffers
+                                        */
+       u32 sample_rate;                /* Card sample rate in Hz */
+       u8 digital_mode;                /* Current digital mode
+                                        * (see DIGITAL_MODE_*)
+                                        */
+       u8 spdif_status;                /* Gina20, Darla20, Darla24 - only */
+       u8 clock_state;                 /* Gina20, Darla20, Darla24 - only */
+       u8 input_clock;                 /* Currently selected sample clock
+                                        * source
+                                        */
+       u8 output_clock;                /* Layla20 only */
+       char meters_enabled;            /* VU-meters status */
+       char asic_loaded;               /* Set TRUE when ASIC loaded */
+       char bad_board;                 /* Set TRUE if DSP won't load */
+       char professional_spdif;        /* 0 = consumer; 1 = professional */
+       char non_audio_spdif;           /* 3G - only */
+       char digital_in_automute;       /* Gina24, Layla24, Mona - only */
+       char has_phantom_power;
+       char hasnt_input_nominal_level; /* Gina3G */
+       char phantom_power;             /* Gina3G - only */
+       char has_midi;
+       char midi_input_enabled;
+
+#ifdef ECHOCARD_ECHO3G
+       /* External module -dependent pipe and bus indexes */
+       char px_digital_out, px_analog_in, px_digital_in, px_num;
+       char bx_digital_out, bx_analog_in, bx_digital_in, bx_num;
+#endif
+
+       char nominal_level[ECHO_MAXAUDIOPIPES]; /* True == -10dBV
+                                                * False == +4dBu */
+       s8 input_gain[ECHO_MAXAUDIOINPUTS];     /* Input level -50..+50
+                                                * unit is 0.5dB */
+       s8 output_gain[ECHO_MAXAUDIOOUTPUTS];   /* Output level -128..+6 dB
+                                                * (-128=muted) */
+       s8 monitor_gain[ECHO_MAXAUDIOOUTPUTS][ECHO_MAXAUDIOINPUTS];
+               /* -128..+6 dB */
+       s8 vmixer_gain[ECHO_MAXAUDIOOUTPUTS][ECHO_MAXAUDIOOUTPUTS];
+               /* -128..+6 dB */
+
+       u16 digital_modes;              /* Bitmask of supported modes
+                                        * (see ECHOCAPS_HAS_DIGITAL_MODE_*) */
+       u16 input_clock_types;          /* Suppoted input clock types */
+       u16 output_clock_types;         /* Suppoted output clock types -
+                                        * Layla20 only */
+       u16 device_id, subdevice_id;
+       u16 *dsp_code;                  /* Current DSP code loaded,
+                                        * NULL if nothing loaded */
+       const struct firmware *dsp_code_to_load;/* DSP code to load */
+       const struct firmware *asic_code;       /* Current ASIC code */
+       u32 comm_page_phys;                     /* Physical address of the
+                                                * memory seen by DSP */
+       volatile u32 __iomem *dsp_registers;    /* DSP's register base */
+       u32 active_mask;                        /* Chs. active mask or
+                                                * punks out */
+
+#ifdef ECHOCARD_HAS_MIDI
+       u16 mtc_state;                          /* State for MIDI input parsing state machine */
+       u8 midi_buffer[MIDI_IN_BUFFER_SIZE];
+#endif
+};
+
+
+static int init_dsp_comm_page(struct echoaudio *chip);
+static int init_line_levels(struct echoaudio *chip);
+static int free_pipes(struct echoaudio *chip, struct audiopipe *pipe);
+static int load_firmware(struct echoaudio *chip);
+static int wait_handshake(struct echoaudio *chip);
+static int send_vector(struct echoaudio *chip, u32 command);
+static int get_firmware(const struct firmware **fw_entry,
+                       const struct firmware *frm, struct echoaudio *chip);
+static void free_firmware(const struct firmware *fw_entry);
+
+#ifdef ECHOCARD_HAS_MIDI
+static int enable_midi_input(struct echoaudio *chip, char enable);
+static int midi_service_irq(struct echoaudio *chip);
+static int __devinit snd_echo_midi_create(struct snd_card *card,
+                                         struct echoaudio *chip);
+#endif
+
+
+static inline void clear_handshake(struct echoaudio *chip)
+{
+       chip->comm_page->handshake = 0;
+}
+
+static inline u32 get_dsp_register(struct echoaudio *chip, u32 index)
+{
+       return readl(&chip->dsp_registers[index]);
+}
+
+static inline void set_dsp_register(struct echoaudio *chip, u32 index,
+                                   u32 value)
+{
+       writel(value, &chip->dsp_registers[index]);
+}
+
+
+/* Pipe and bus indexes. PX_* and BX_* are defined as chip->px_* and chip->bx_*
+for 3G cards because they depend on the external box. They are integer
+constants for all other cards.
+Never use those defines directly, use the following functions instead. */
+
+static inline int px_digital_out(const struct echoaudio *chip)
+{
+       return PX_DIGITAL_OUT;
+}
+
+static inline int px_analog_in(const struct echoaudio *chip)
+{
+       return PX_ANALOG_IN;
+}
+
+static inline int px_digital_in(const struct echoaudio *chip)
+{
+       return PX_DIGITAL_IN;
+}
+
+static inline int px_num(const struct echoaudio *chip)
+{
+       return PX_NUM;
+}
+
+static inline int bx_digital_out(const struct echoaudio *chip)
+{
+       return BX_DIGITAL_OUT;
+}
+
+static inline int bx_analog_in(const struct echoaudio *chip)
+{
+       return BX_ANALOG_IN;
+}
+
+static inline int bx_digital_in(const struct echoaudio *chip)
+{
+       return BX_DIGITAL_IN;
+}
+
+static inline int bx_num(const struct echoaudio *chip)
+{
+       return BX_NUM;
+}
+
+static inline int num_pipes_out(const struct echoaudio *chip)
+{
+       return px_analog_in(chip);
+}
+
+static inline int num_pipes_in(const struct echoaudio *chip)
+{
+       return px_num(chip) - px_analog_in(chip);
+}
+
+static inline int num_busses_out(const struct echoaudio *chip)
+{
+       return bx_analog_in(chip);
+}
+
+static inline int num_busses_in(const struct echoaudio *chip)
+{
+       return bx_num(chip) - bx_analog_in(chip);
+}
+
+static inline int num_analog_busses_out(const struct echoaudio *chip)
+{
+       return bx_digital_out(chip);
+}
+
+static inline int num_analog_busses_in(const struct echoaudio *chip)
+{
+       return bx_digital_in(chip) - bx_analog_in(chip);
+}
+
+static inline int num_digital_busses_out(const struct echoaudio *chip)
+{
+       return num_busses_out(chip) - num_analog_busses_out(chip);
+}
+
+static inline int num_digital_busses_in(const struct echoaudio *chip)
+{
+       return num_busses_in(chip) - num_analog_busses_in(chip);
+}
+
+/* The monitor array is a one-dimensional array; compute the offset
+ * into the array */
+static inline int monitor_index(const struct echoaudio *chip, int out, int in)
+{
+       return out * num_busses_in(chip) + in;
+}
+
+
+#ifndef pci_device
+#define pci_device(chip) (&chip->pci->dev)
+#endif
+
+
+#endif /* _ECHOAUDIO_H_ */
diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c
new file mode 100644 (file)
index 0000000..9f439ea
--- /dev/null
@@ -0,0 +1,431 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+
+/* These functions are common for all "3G" cards */
+
+
+static int check_asic_status(struct echoaudio *chip)
+{
+       u32 box_status;
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->comm_page->ext_box_status =
+               __constant_cpu_to_le32(E3G_ASIC_NOT_LOADED);
+       chip->asic_loaded = FALSE;
+       clear_handshake(chip);
+       send_vector(chip, DSP_VC_TEST_ASIC);
+
+       if (wait_handshake(chip)) {
+               chip->dsp_code = NULL;
+               return -EIO;
+       }
+
+       box_status = le32_to_cpu(chip->comm_page->ext_box_status);
+       DE_INIT(("box_status=%x\n", box_status));
+       if (box_status == E3G_ASIC_NOT_LOADED)
+               return -ENODEV;
+
+       chip->asic_loaded = TRUE;
+       return box_status & E3G_BOX_TYPE_MASK;
+}
+
+
+
+static inline u32 get_frq_reg(struct echoaudio *chip)
+{
+       return le32_to_cpu(chip->comm_page->e3g_frq_register);
+}
+
+
+
+/* Most configuration of 3G cards is accomplished by writing the control
+register. write_control_reg sends the new control register value to the DSP. */
+static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
+                            char force)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+
+       DE_ACT(("WriteControlReg: Setting 0x%x, 0x%x\n", ctl, frq));
+
+       ctl = cpu_to_le32(ctl);
+       frq = cpu_to_le32(frq);
+
+       if (ctl != chip->comm_page->control_register ||
+           frq != chip->comm_page->e3g_frq_register || force) {
+               chip->comm_page->e3g_frq_register = frq;
+               chip->comm_page->control_register = ctl;
+               clear_handshake(chip);
+               return send_vector(chip, DSP_VC_WRITE_CONTROL_REG);
+       }
+
+       DE_ACT(("WriteControlReg: not written, no change\n"));
+       return 0;
+}
+
+
+
+/* Set the digital mode - currently for Gina24, Layla24, Mona, 3G */
+static int set_digital_mode(struct echoaudio *chip, u8 mode)
+{
+       u8 previous_mode;
+       int err, i, o;
+
+       /* All audio channels must be closed before changing the digital mode */
+       snd_assert(!chip->pipe_alloc_mask, return -EAGAIN);
+
+       snd_assert(chip->digital_modes & (1 << mode), return -EINVAL);
+
+       previous_mode = chip->digital_mode;
+       err = dsp_set_digital_mode(chip, mode);
+
+       /* If we successfully changed the digital mode from or to ADAT,
+        * then make sure all output, input and monitor levels are
+        * updated by the DSP comm object. */
+       if (err >= 0 && previous_mode != mode &&
+           (previous_mode == DIGITAL_MODE_ADAT || mode == DIGITAL_MODE_ADAT)) {
+               spin_lock_irq(&chip->lock);
+               for (o = 0; o < num_busses_out(chip); o++)
+                       for (i = 0; i < num_busses_in(chip); i++)
+                               set_monitor_gain(chip, o, i,
+                                                chip->monitor_gain[o][i]);
+
+#ifdef ECHOCARD_HAS_INPUT_GAIN
+               for (i = 0; i < num_busses_in(chip); i++)
+                       set_input_gain(chip, i, chip->input_gain[i]);
+               update_input_line_level(chip);
+#endif
+
+               for (o = 0; o < num_busses_out(chip); o++)
+                       set_output_gain(chip, o, chip->output_gain[o]);
+               update_output_line_level(chip);
+               spin_unlock_irq(&chip->lock);
+       }
+
+       return err;
+}
+
+
+
+static u32 set_spdif_bits(struct echoaudio *chip, u32 control_reg, u32 rate)
+{
+       control_reg &= E3G_SPDIF_FORMAT_CLEAR_MASK;
+
+       switch (rate) {
+       case 32000 :
+               control_reg |= E3G_SPDIF_SAMPLE_RATE0 | E3G_SPDIF_SAMPLE_RATE1;
+               break;
+       case 44100 :
+               if (chip->professional_spdif)
+                       control_reg |= E3G_SPDIF_SAMPLE_RATE0;
+               break;
+       case 48000 :
+               control_reg |= E3G_SPDIF_SAMPLE_RATE1;
+               break;
+       }
+
+       if (chip->professional_spdif)
+               control_reg |= E3G_SPDIF_PRO_MODE;
+
+       if (chip->non_audio_spdif)
+               control_reg |= E3G_SPDIF_NOT_AUDIO;
+
+       control_reg |= E3G_SPDIF_24_BIT | E3G_SPDIF_TWO_CHANNEL |
+               E3G_SPDIF_COPY_PERMIT;
+
+       return control_reg;
+}
+
+
+
+/* Set the S/PDIF output format */
+static int set_professional_spdif(struct echoaudio *chip, char prof)
+{
+       u32 control_reg;
+
+       control_reg = le32_to_cpu(chip->comm_page->control_register);
+       chip->professional_spdif = prof;
+       control_reg = set_spdif_bits(chip, control_reg, chip->sample_rate);
+       return write_control_reg(chip, control_reg, get_frq_reg(chip), 0);
+}
+
+
+
+/* detect_input_clocks() returns a bitmask consisting of all the input clocks
+currently connected to the hardware; this changes as the user connects and
+disconnects clock inputs. You should use this information to determine which
+clocks the user is allowed to select. */
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       u32 clocks_from_dsp, clock_bits;
+
+       /* Map the DSP clock detect bits to the generic driver clock
+        * detect bits */
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       clock_bits = ECHO_CLOCK_BIT_INTERNAL;
+
+       if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_WORD)
+               clock_bits |= ECHO_CLOCK_BIT_WORD;
+
+       switch(chip->digital_mode) {
+       case DIGITAL_MODE_SPDIF_RCA:
+       case DIGITAL_MODE_SPDIF_OPTICAL:
+               if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_SPDIF)
+                       clock_bits |= ECHO_CLOCK_BIT_SPDIF;
+               break;
+       case DIGITAL_MODE_ADAT:
+               if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_ADAT)
+                       clock_bits |= ECHO_CLOCK_BIT_ADAT;
+               break;
+       }
+
+       return clock_bits;
+}
+
+
+
+static int load_asic(struct echoaudio *chip)
+{
+       int box_type, err;
+
+       if (chip->asic_loaded)
+               return 0;
+
+       /* Give the DSP a few milliseconds to settle down */
+       mdelay(2);
+
+       err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC,
+                               &card_fw[FW_3G_ASIC]);
+       if (err < 0)
+               return err;
+
+       chip->asic_code = &card_fw[FW_3G_ASIC];
+
+       /* Now give the new ASIC a little time to set up */
+       mdelay(2);
+       /* See if it worked */
+       box_type = check_asic_status(chip);
+
+       /* Set up the control register if the load succeeded -
+        * 48 kHz, internal clock, S/PDIF RCA mode */
+       if (box_type >= 0) {
+               err = write_control_reg(chip, E3G_48KHZ,
+                                       E3G_FREQ_REG_DEFAULT, TRUE);
+               if (err < 0)
+                       return err;
+       }
+
+       return box_type;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u32 control_reg, clock, base_rate, frq_reg;
+
+       /* Only set the clock for internal mode. */
+       if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
+               DE_ACT(("set_sample_rate: Cannot set sample rate - "
+                       "clock not set to CLK_CLOCKININTERNAL\n"));
+               /* Save the rate anyhow */
+               chip->comm_page->sample_rate = cpu_to_le32(rate);
+               chip->sample_rate = rate;
+               set_input_clock(chip, chip->input_clock);
+               return 0;
+       }
+
+       snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
+                  return -EINVAL);
+
+       clock = 0;
+       control_reg = le32_to_cpu(chip->comm_page->control_register);
+       control_reg &= E3G_CLOCK_CLEAR_MASK;
+
+       switch (rate) {
+       case 96000:
+               clock = E3G_96KHZ;
+               break;
+       case 88200:
+               clock = E3G_88KHZ;
+               break;
+       case 48000:
+               clock = E3G_48KHZ;
+               break;
+       case 44100:
+               clock = E3G_44KHZ;
+               break;
+       case 32000:
+               clock = E3G_32KHZ;
+               break;
+       default:
+               clock = E3G_CONTINUOUS_CLOCK;
+               if (rate > 50000)
+                       clock |= E3G_DOUBLE_SPEED_MODE;
+               break;
+       }
+
+       control_reg |= clock;
+       control_reg = set_spdif_bits(chip, control_reg, rate);
+
+       base_rate = rate;
+       if (base_rate > 50000)
+               base_rate /= 2;
+       if (base_rate < 32000)
+               base_rate = 32000;
+
+       frq_reg = E3G_MAGIC_NUMBER / base_rate - 2;
+       if (frq_reg > E3G_FREQ_REG_MAX)
+               frq_reg = E3G_FREQ_REG_MAX;
+
+       chip->comm_page->sample_rate = cpu_to_le32(rate);       /* ignored by the DSP */
+       chip->sample_rate = rate;
+       DE_ACT(("SetSampleRate: %d clock %x\n", rate, control_reg));
+
+       /* Tell the DSP about it - DSP reads both control reg & freq reg */
+       return write_control_reg(chip, control_reg, frq_reg, 0);
+}
+
+
+
+/* Set the sample clock source to internal, S/PDIF, ADAT */
+static int set_input_clock(struct echoaudio *chip, u16 clock)
+{
+       u32 control_reg, clocks_from_dsp;
+
+       DE_ACT(("set_input_clock:\n"));
+
+       /* Mask off the clock select bits */
+       control_reg = le32_to_cpu(chip->comm_page->control_register) &
+               E3G_CLOCK_CLEAR_MASK;
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       switch (clock) {
+       case ECHO_CLOCK_INTERNAL:
+               DE_ACT(("Set Echo3G clock to INTERNAL\n"));
+               chip->input_clock = ECHO_CLOCK_INTERNAL;
+               return set_sample_rate(chip, chip->sample_rate);
+       case ECHO_CLOCK_SPDIF:
+               if (chip->digital_mode == DIGITAL_MODE_ADAT)
+                       return -EAGAIN;
+               DE_ACT(("Set Echo3G clock to SPDIF\n"));
+               control_reg |= E3G_SPDIF_CLOCK;
+               if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_SPDIF96)
+                       control_reg |= E3G_DOUBLE_SPEED_MODE;
+               else
+                       control_reg &= ~E3G_DOUBLE_SPEED_MODE;
+               break;
+       case ECHO_CLOCK_ADAT:
+               if (chip->digital_mode != DIGITAL_MODE_ADAT)
+                       return -EAGAIN;
+               DE_ACT(("Set Echo3G clock to ADAT\n"));
+               control_reg |= E3G_ADAT_CLOCK;
+               control_reg &= ~E3G_DOUBLE_SPEED_MODE;
+               break;
+       case ECHO_CLOCK_WORD:
+               DE_ACT(("Set Echo3G clock to WORD\n"));
+               control_reg |= E3G_WORD_CLOCK;
+               if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_WORD96)
+                       control_reg |= E3G_DOUBLE_SPEED_MODE;
+               else
+                       control_reg &= ~E3G_DOUBLE_SPEED_MODE;
+               break;
+       default:
+               DE_ACT(("Input clock 0x%x not supported for Echo3G\n", clock));
+               return -EINVAL;
+       }
+
+       chip->input_clock = clock;
+       return write_control_reg(chip, control_reg, get_frq_reg(chip), 1);
+}
+
+
+
+static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
+{
+       u32 control_reg;
+       int err, incompatible_clock;
+
+       /* Set clock to "internal" if it's not compatible with the new mode */
+       incompatible_clock = FALSE;
+       switch (mode) {
+       case DIGITAL_MODE_SPDIF_OPTICAL:
+       case DIGITAL_MODE_SPDIF_RCA:
+               if (chip->input_clock == ECHO_CLOCK_ADAT)
+                       incompatible_clock = TRUE;
+               break;
+       case DIGITAL_MODE_ADAT:
+               if (chip->input_clock == ECHO_CLOCK_SPDIF)
+                       incompatible_clock = TRUE;
+               break;
+       default:
+               DE_ACT(("Digital mode not supported: %d\n", mode));
+               return -EINVAL;
+       }
+
+       spin_lock_irq(&chip->lock);
+
+       if (incompatible_clock) {
+               chip->sample_rate = 48000;
+               set_input_clock(chip, ECHO_CLOCK_INTERNAL);
+       }
+
+       /* Clear the current digital mode */
+       control_reg = le32_to_cpu(chip->comm_page->control_register);
+       control_reg &= E3G_DIGITAL_MODE_CLEAR_MASK;
+
+       /* Tweak the control reg */
+       switch (mode) {
+       case DIGITAL_MODE_SPDIF_OPTICAL:
+               control_reg |= E3G_SPDIF_OPTICAL_MODE;
+               break;
+       case DIGITAL_MODE_SPDIF_RCA:
+               /* E3G_SPDIF_OPTICAL_MODE bit cleared */
+               break;
+       case DIGITAL_MODE_ADAT:
+               control_reg |= E3G_ADAT_MODE;
+               control_reg &= ~E3G_DOUBLE_SPEED_MODE;  /* @@ useless */
+               break;
+       }
+
+       err = write_control_reg(chip, control_reg, get_frq_reg(chip), 1);
+       spin_unlock_irq(&chip->lock);
+       if (err < 0)
+               return err;
+       chip->digital_mode = mode;
+
+       DE_ACT(("set_digital_mode(%d)\n", chip->digital_mode));
+       return incompatible_clock;
+}
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c
new file mode 100644 (file)
index 0000000..42afa83
--- /dev/null
@@ -0,0 +1,1125 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+#if PAGE_SIZE < 4096
+#error PAGE_SIZE is < 4k
+#endif
+
+static int restore_dsp_rettings(struct echoaudio *chip);
+
+
+/* Some vector commands involve the DSP reading or writing data to and from the
+comm page; if you send one of these commands to the DSP, it will complete the
+command and then write a non-zero value to the Handshake field in the
+comm page.  This function waits for the handshake to show up. */
+static int wait_handshake(struct echoaudio *chip)
+{
+       int i;
+
+       /* Wait up to 10ms for the handshake from the DSP */
+       for (i = 0; i < HANDSHAKE_TIMEOUT; i++) {
+               /* Look for the handshake value */
+               if (chip->comm_page->handshake) {
+                       /*if (i)  DE_ACT(("Handshake time: %d\n", i));*/
+                       return 0;
+               }
+               udelay(1);
+       }
+
+       snd_printk(KERN_ERR "wait_handshake(): Timeout waiting for DSP\n");
+       return -EBUSY;
+}
+
+
+
+/* Much of the interaction between the DSP and the driver is done via vector
+commands; send_vector writes a vector command to the DSP.  Typically, this
+causes the DSP to read or write fields in the comm page.
+PCI posting is not required thanks to the handshake logic. */
+static int send_vector(struct echoaudio *chip, u32 command)
+{
+       int i;
+
+       wmb();  /* Flush all pending writes before sending the command */
+
+       /* Wait up to 100ms for the "vector busy" bit to be off */
+       for (i = 0; i < VECTOR_BUSY_TIMEOUT; i++) {
+               if (!(get_dsp_register(chip, CHI32_VECTOR_REG) &
+                     CHI32_VECTOR_BUSY)) {
+                       set_dsp_register(chip, CHI32_VECTOR_REG, command);
+                       /*if (i)  DE_ACT(("send_vector time: %d\n", i));*/
+                       return 0;
+               }
+               udelay(1);
+       }
+
+       DE_ACT((KERN_ERR "timeout on send_vector\n"));
+       return -EBUSY;
+}
+
+
+
+/* write_dsp writes a 32-bit value to the DSP; this is used almost
+exclusively for loading the DSP. */
+static int write_dsp(struct echoaudio *chip, u32 data)
+{
+       u32 status, i;
+
+       for (i = 0; i < 10000000; i++) {        /* timeout = 10s */
+               status = get_dsp_register(chip, CHI32_STATUS_REG);
+               if ((status & CHI32_STATUS_HOST_WRITE_EMPTY) != 0) {
+                       set_dsp_register(chip, CHI32_DATA_REG, data);
+                       wmb();                  /* write it immediately */
+                       return 0;
+               }
+               udelay(1);
+               cond_resched();
+       }
+
+       chip->bad_board = TRUE;         /* Set TRUE until DSP re-loaded */
+       DE_ACT((KERN_ERR "write_dsp: Set bad_board to TRUE\n"));
+       return -EIO;
+}
+
+
+
+/* read_dsp reads a 32-bit value from the DSP; this is used almost
+exclusively for loading the DSP and checking the status of the ASIC. */
+static int read_dsp(struct echoaudio *chip, u32 *data)
+{
+       u32 status, i;
+
+       for (i = 0; i < READ_DSP_TIMEOUT; i++) {
+               status = get_dsp_register(chip, CHI32_STATUS_REG);
+               if ((status & CHI32_STATUS_HOST_READ_FULL) != 0) {
+                       *data = get_dsp_register(chip, CHI32_DATA_REG);
+                       return 0;
+               }
+               udelay(1);
+               cond_resched();
+       }
+
+       chip->bad_board = TRUE;         /* Set TRUE until DSP re-loaded */
+       DE_INIT((KERN_ERR "read_dsp: Set bad_board to TRUE\n"));
+       return -EIO;
+}
+
+
+
+/****************************************************************************
+       Firmware loading functions
+ ****************************************************************************/
+
+/* This function is used to read back the serial number from the DSP;
+this is triggered by the SET_COMMPAGE_ADDR command.
+Only some early Echogals products have serial numbers in the ROM;
+the serial number is not used, but you still need to do this as
+part of the DSP load process. */
+static int read_sn(struct echoaudio *chip)
+{
+       int i;
+       u32 sn[6];
+
+       for (i = 0; i < 5; i++) {
+               if (read_dsp(chip, &sn[i])) {
+                       snd_printk(KERN_ERR "Failed to read serial number\n");
+                       return -EIO;
+               }
+       }
+       DE_INIT(("Read serial number %08x %08x %08x %08x %08x\n",
+                sn[0], sn[1], sn[2], sn[3], sn[4]));
+       return 0;
+}
+
+
+
+#ifndef ECHOCARD_HAS_ASIC
+/* This card has no ASIC, just return ok */
+static inline int check_asic_status(struct echoaudio *chip)
+{
+       chip->asic_loaded = TRUE;
+       return 0;
+}
+
+#endif /* !ECHOCARD_HAS_ASIC */
+
+
+
+#ifdef ECHOCARD_HAS_ASIC
+
+/* Load ASIC code - done after the DSP is loaded */
+static int load_asic_generic(struct echoaudio *chip, u32 cmd,
+                            const struct firmware *asic)
+{
+       const struct firmware *fw;
+       int err;
+       u32 i, size;
+       u8 *code;
+
+       if ((err = get_firmware(&fw, asic, chip)) < 0) {
+               snd_printk(KERN_WARNING "Firmware not found !\n");
+               return err;
+       }
+
+       code = (u8 *)fw->data;
+       size = fw->size;
+
+       /* Send the "Here comes the ASIC" command */
+       if (write_dsp(chip, cmd) < 0)
+               goto la_error;
+
+       /* Write length of ASIC file in bytes */
+       if (write_dsp(chip, size) < 0)
+               goto la_error;
+
+       for (i = 0; i < size; i++) {
+               if (write_dsp(chip, code[i]) < 0)
+                       goto la_error;
+       }
+
+       DE_INIT(("ASIC loaded\n"));
+       free_firmware(fw);
+       return 0;
+
+la_error:
+       DE_INIT(("failed on write_dsp\n"));
+       free_firmware(fw);
+       return -EIO;
+}
+
+#endif /* ECHOCARD_HAS_ASIC */
+
+
+
+#ifdef DSP_56361
+
+/* Install the resident loader for 56361 DSPs;  The resident loader is on
+the EPROM on the board for 56301 DSP. The resident loader is a tiny little
+program that is used to load the real DSP code. */
+static int install_resident_loader(struct echoaudio *chip)
+{
+       u32 address;
+       int index, words, i;
+       u16 *code;
+       u32 status;
+       const struct firmware *fw;
+
+       /* 56361 cards only!  This check is required by the old 56301-based
+       Mona and Gina24 */
+       if (chip->device_id != DEVICE_ID_56361)
+               return 0;
+
+       /* Look to see if the resident loader is present.  If the resident
+       loader is already installed, host flag 5 will be on. */
+       status = get_dsp_register(chip, CHI32_STATUS_REG);
+       if (status & CHI32_STATUS_REG_HF5) {
+               DE_INIT(("Resident loader already installed; status is 0x%x\n",
+                        status));
+               return 0;
+       }
+
+       if ((i = get_firmware(&fw, &card_fw[FW_361_LOADER], chip)) < 0) {
+               snd_printk(KERN_WARNING "Firmware not found !\n");
+               return i;
+       }
+
+       /* The DSP code is an array of 16 bit words.  The array is divided up
+       into sections.  The first word of each section is the size in words,
+       followed by the section type.
+       Since DSP addresses and data are 24 bits wide, they each take up two
+       16 bit words in the array.
+       This is a lot like the other loader loop, but it's not a loop, you
+       don't write the memory type, and you don't write a zero at the end. */
+
+       /* Set DSP format bits for 24 bit mode */
+       set_dsp_register(chip, CHI32_CONTROL_REG,
+                        get_dsp_register(chip, CHI32_CONTROL_REG) | 0x900);
+
+       code = (u16 *)fw->data;
+
+       /* Skip the header section; the first word in the array is the size
+       of the first section, so the first real section of code is pointed
+       to by Code[0]. */
+       index = code[0];
+
+       /* Skip the section size, LRS block type, and DSP memory type */
+       index += 3;
+
+       /* Get the number of DSP words to write */
+       words = code[index++];
+
+       /* Get the DSP address for this block; 24 bits, so build from two words */
+       address = ((u32)code[index] << 16) + code[index + 1];
+       index += 2;
+
+       /* Write the count to the DSP */
+       if (write_dsp(chip, words)) {
+               DE_INIT(("install_resident_loader: Failed to write word count!\n"));
+               goto irl_error;
+       }
+       /* Write the DSP address */
+       if (write_dsp(chip, address)) {
+               DE_INIT(("install_resident_loader: Failed to write DSP address!\n"));
+               goto irl_error;
+       }
+       /* Write out this block of code to the DSP */
+       for (i = 0; i < words; i++) {
+               u32 data;
+
+               data = ((u32)code[index] << 16) + code[index + 1];
+               if (write_dsp(chip, data)) {
+                       DE_INIT(("install_resident_loader: Failed to write DSP code\n"));
+                       goto irl_error;
+               }
+               index += 2;
+       }
+
+       /* Wait for flag 5 to come up */
+       for (i = 0; i < 200; i++) {     /* Timeout is 50us * 200 = 10ms */
+               udelay(50);
+               status = get_dsp_register(chip, CHI32_STATUS_REG);
+               if (status & CHI32_STATUS_REG_HF5)
+                       break;
+       }
+
+       if (i == 200) {
+               DE_INIT(("Resident loader failed to set HF5\n"));
+               goto irl_error;
+       }
+
+       DE_INIT(("Resident loader successfully installed\n"));
+       free_firmware(fw);
+       return 0;
+
+irl_error:
+       free_firmware(fw);
+       return -EIO;
+}
+
+#endif /* DSP_56361 */
+
+
+static int load_dsp(struct echoaudio *chip, u16 *code)
+{
+       u32 address, data;
+       int index, words, i;
+
+       if (chip->dsp_code == code) {
+               DE_INIT(("DSP is already loaded!\n"));
+               return 0;
+       }
+       chip->bad_board = TRUE;         /* Set TRUE until DSP loaded */
+       chip->dsp_code = NULL;          /* Current DSP code not loaded */
+       chip->asic_loaded = FALSE;      /* Loading the DSP code will reset the ASIC */
+
+       DE_INIT(("load_dsp: Set bad_board to TRUE\n"));
+
+       /* If this board requires a resident loader, install it. */
+#ifdef DSP_56361
+       if ((i = install_resident_loader(chip)) < 0)
+               return i;
+#endif
+
+       /* Send software reset command */
+       if (send_vector(chip, DSP_VC_RESET) < 0) {
+               DE_INIT(("LoadDsp: send_vector DSP_VC_RESET failed, Critical Failure\n"));
+               return -EIO;
+       }
+       /* Delay 10us */
+       udelay(10);
+
+       /* Wait 10ms for HF3 to indicate that software reset is complete */
+       for (i = 0; i < 1000; i++) {    /* Timeout is 10us * 1000 = 10ms */
+               if (get_dsp_register(chip, CHI32_STATUS_REG) &
+                   CHI32_STATUS_REG_HF3)
+                       break;
+               udelay(10);
+       }
+
+       if (i == 1000) {
+               DE_INIT(("load_dsp: Timeout waiting for CHI32_STATUS_REG_HF3\n"));
+               return -EIO;
+       }
+
+       /* Set DSP format bits for 24 bit mode now that soft reset is done */
+       set_dsp_register(chip, CHI32_CONTROL_REG,
+                        get_dsp_register(chip, CHI32_CONTROL_REG) | 0x900);
+
+       /* Main loader loop */
+
+       index = code[0];
+       for (;;) {
+               int block_type, mem_type;
+
+               /* Total Block Size */
+               index++;
+
+               /* Block Type */
+               block_type = code[index];
+               if (block_type == 4)    /* We're finished */
+                       break;
+
+               index++;
+
+               /* Memory Type  P=0,X=1,Y=2 */
+               mem_type = code[index++];
+
+               /* Block Code Size */
+               words = code[index++];
+               if (words == 0)         /* We're finished */
+                       break;
+
+               /* Start Address */
+               address = ((u32)code[index] << 16) + code[index + 1];
+               index += 2;
+
+               if (write_dsp(chip, words) < 0) {
+                       DE_INIT(("load_dsp: failed to write number of DSP words\n"));
+                       return -EIO;
+               }
+               if (write_dsp(chip, address) < 0) {
+                       DE_INIT(("load_dsp: failed to write DSP address\n"));
+                       return -EIO;
+               }
+               if (write_dsp(chip, mem_type) < 0) {
+                       DE_INIT(("load_dsp: failed to write DSP memory type\n"));
+                       return -EIO;
+               }
+               /* Code */
+               for (i = 0; i < words; i++, index+=2) {
+                       data = ((u32)code[index] << 16) + code[index + 1];
+                       if (write_dsp(chip, data) < 0) {
+                               DE_INIT(("load_dsp: failed to write DSP data\n"));
+                               return -EIO;
+                       }
+               }
+       }
+
+       if (write_dsp(chip, 0) < 0) {   /* We're done!!! */
+               DE_INIT(("load_dsp: Failed to write final zero\n"));
+               return -EIO;
+       }
+       udelay(10);
+
+       for (i = 0; i < 5000; i++) {    /* Timeout is 100us * 5000 = 500ms */
+               /* Wait for flag 4 - indicates that the DSP loaded OK */
+               if (get_dsp_register(chip, CHI32_STATUS_REG) &
+                   CHI32_STATUS_REG_HF4) {
+                       set_dsp_register(chip, CHI32_CONTROL_REG,
+                                        get_dsp_register(chip, CHI32_CONTROL_REG) & ~0x1b00);
+
+                       if (write_dsp(chip, DSP_FNC_SET_COMMPAGE_ADDR) < 0) {
+                               DE_INIT(("load_dsp: Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n"));
+                               return -EIO;
+                       }
+
+                       if (write_dsp(chip, chip->comm_page_phys) < 0) {
+                               DE_INIT(("load_dsp: Failed to write comm page address\n"));
+                               return -EIO;
+                       }
+
+                       /* Get the serial number via slave mode.
+                       This is triggered by the SET_COMMPAGE_ADDR command.
+                       We don't actually use the serial number but we have to
+                       get it as part of the DSP init voodoo. */
+                       if (read_sn(chip) < 0) {
+                               DE_INIT(("load_dsp: Failed to read serial number\n"));
+                               return -EIO;
+                       }
+
+                       chip->dsp_code = code;          /* Show which DSP code loaded */
+                       chip->bad_board = FALSE;        /* DSP OK */
+                       DE_INIT(("load_dsp: OK!\n"));
+                       return 0;
+               }
+               udelay(100);
+       }
+
+       DE_INIT(("load_dsp: DSP load timed out waiting for HF4\n"));
+       return -EIO;
+}
+
+
+
+/* load_firmware takes care of loading the DSP and any ASIC code. */
+static int load_firmware(struct echoaudio *chip)
+{
+       const struct firmware *fw;
+       int box_type, err;
+
+       snd_assert(chip->dsp_code_to_load && chip->comm_page, return -EPERM);
+
+       /* See if the ASIC is present and working - only if the DSP is already loaded */
+       if (chip->dsp_code) {
+               if ((box_type = check_asic_status(chip)) >= 0)
+                       return box_type;
+               /* ASIC check failed; force the DSP to reload */
+               chip->dsp_code = NULL;
+       }
+
+       if ((err = get_firmware(&fw, chip->dsp_code_to_load, chip)) < 0)
+               return err;
+       err = load_dsp(chip, (u16 *)fw->data);
+       free_firmware(fw);
+       if (err < 0)
+               return err;
+
+       if ((box_type = load_asic(chip)) < 0)
+               return box_type;        /* error */
+
+       if ((err = restore_dsp_rettings(chip)) < 0)
+               return err;
+
+       return box_type;
+}
+
+
+
+/****************************************************************************
+       Mixer functions
+ ****************************************************************************/
+
+#if defined(ECHOCARD_HAS_INPUT_NOMINAL_LEVEL) || \
+       defined(ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL)
+
+/* Set the nominal level for an input or output bus (true = -10dBV, false = +4dBu) */
+static int set_nominal_level(struct echoaudio *chip, u16 index, char consumer)
+{
+       snd_assert(index < num_busses_out(chip) + num_busses_in(chip),
+                  return -EINVAL);
+
+       /* Wait for the handshake (OK even if ASIC is not loaded) */
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->nominal_level[index] = consumer;
+
+       if (consumer)
+               chip->comm_page->nominal_level_mask |= cpu_to_le32(1 << index);
+       else
+               chip->comm_page->nominal_level_mask &= ~cpu_to_le32(1 << index);
+
+       return 0;
+}
+
+#endif /* ECHOCARD_HAS_*_NOMINAL_LEVEL */
+
+
+
+/* Set the gain for a single physical output channel (dB). */
+static int set_output_gain(struct echoaudio *chip, u16 channel, s8 gain)
+{
+       snd_assert(channel < num_busses_out(chip), return -EINVAL);
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       /* Save the new value */
+       chip->output_gain[channel] = gain;
+       chip->comm_page->line_out_level[channel] = gain;
+       return 0;
+}
+
+
+
+#ifdef ECHOCARD_HAS_MONITOR
+/* Set the monitor level from an input bus to an output bus. */
+static int set_monitor_gain(struct echoaudio *chip, u16 output, u16 input,
+                           s8 gain)
+{
+       snd_assert(output < num_busses_out(chip) &&
+                  input < num_busses_in(chip), return -EINVAL);
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->monitor_gain[output][input] = gain;
+       chip->comm_page->monitors[monitor_index(chip, output, input)] = gain;
+       return 0;
+}
+#endif /* ECHOCARD_HAS_MONITOR */
+
+
+/* Tell the DSP to read and update output, nominal & monitor levels in comm page. */
+static int update_output_line_level(struct echoaudio *chip)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_UPDATE_OUTVOL);
+}
+
+
+
+/* Tell the DSP to read and update input levels in comm page */
+static int update_input_line_level(struct echoaudio *chip)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_UPDATE_INGAIN);
+}
+
+
+
+/* set_meters_on turns the meters on or off.  If meters are turned on, the DSP
+will write the meter and clock detect values to the comm page at about 30Hz */
+static void set_meters_on(struct echoaudio *chip, char on)
+{
+       if (on && !chip->meters_enabled) {
+               send_vector(chip, DSP_VC_METERS_ON);
+               chip->meters_enabled = 1;
+       } else if (!on && chip->meters_enabled) {
+               send_vector(chip, DSP_VC_METERS_OFF);
+               chip->meters_enabled = 0;
+               memset((s8 *)chip->comm_page->vu_meter, ECHOGAIN_MUTED,
+                      DSP_MAXPIPES);
+               memset((s8 *)chip->comm_page->peak_meter, ECHOGAIN_MUTED,
+                      DSP_MAXPIPES);
+       }
+}
+
+
+
+/* Fill out an the given array using the current values in the comm page.
+Meters are written in the comm page by the DSP in this order:
+ Output busses
+ Input busses
+ Output pipes (vmixer cards only)
+
+This function assumes there are no more than 16 in/out busses or pipes
+Meters is an array [3][16][2] of long. */
+static void get_audio_meters(struct echoaudio *chip, long *meters)
+{
+       int i, m, n;
+
+       m = 0;
+       n = 0;
+       for (i = 0; i < num_busses_out(chip); i++, m++) {
+               meters[n++] = chip->comm_page->vu_meter[m];
+               meters[n++] = chip->comm_page->peak_meter[m];
+       }
+       for (; n < 32; n++)
+               meters[n] = 0;
+
+#ifdef ECHOCARD_ECHO3G
+       m = E3G_MAX_OUTPUTS;    /* Skip unused meters */
+#endif
+
+       for (i = 0; i < num_busses_in(chip); i++, m++) {
+               meters[n++] = chip->comm_page->vu_meter[m];
+               meters[n++] = chip->comm_page->peak_meter[m];
+       }
+       for (; n < 64; n++)
+               meters[n] = 0;
+
+#ifdef ECHOCARD_HAS_VMIXER
+       for (i = 0; i < num_pipes_out(chip); i++, m++) {
+               meters[n++] = chip->comm_page->vu_meter[m];
+               meters[n++] = chip->comm_page->peak_meter[m];
+       }
+#endif
+       for (; n < 96; n++)
+               meters[n] = 0;
+}
+
+
+
+static int restore_dsp_rettings(struct echoaudio *chip)
+{
+       int err;
+       DE_INIT(("restore_dsp_settings\n"));
+
+       if ((err = check_asic_status(chip)) < 0)
+               return err;
+
+       /* @ Gina20/Darla20 only. Should be harmless for other cards. */
+       chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF;
+       chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF;
+       chip->comm_page->handshake = 0xffffffff;
+
+       if ((err = set_sample_rate(chip, chip->sample_rate)) < 0)
+               return err;
+
+       if (chip->meters_enabled)
+               if (send_vector(chip, DSP_VC_METERS_ON) < 0)
+                       return -EIO;
+
+#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
+       if (set_input_clock(chip, chip->input_clock) < 0)
+               return -EIO;
+#endif
+
+#ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH
+       if (set_output_clock(chip, chip->output_clock) < 0)
+               return -EIO;
+#endif
+
+       if (update_output_line_level(chip) < 0)
+               return -EIO;
+
+       if (update_input_line_level(chip) < 0)
+               return -EIO;
+
+#ifdef ECHOCARD_HAS_VMIXER
+       if (update_vmixer_level(chip) < 0)
+               return -EIO;
+#endif
+
+       if (wait_handshake(chip) < 0)
+               return -EIO;
+       clear_handshake(chip);
+
+       DE_INIT(("restore_dsp_rettings done\n"));
+       return send_vector(chip, DSP_VC_UPDATE_FLAGS);
+}
+
+
+
+/****************************************************************************
+       Transport functions
+ ****************************************************************************/
+
+/* set_audio_format() sets the format of the audio data in host memory for
+this pipe.  Note that _MS_ (mono-to-stereo) playback modes are not used by ALSA
+but they are here because they are just mono while capturing */
+static void set_audio_format(struct echoaudio *chip, u16 pipe_index,
+                            const struct audioformat *format)
+{
+       u16 dsp_format;
+
+       dsp_format = DSP_AUDIOFORM_SS_16LE;
+
+       /* Look for super-interleave (no big-endian and 8 bits) */
+       if (format->interleave > 2) {
+               switch (format->bits_per_sample) {
+               case 16:
+                       dsp_format = DSP_AUDIOFORM_SUPER_INTERLEAVE_16LE;
+                       break;
+               case 24:
+                       dsp_format = DSP_AUDIOFORM_SUPER_INTERLEAVE_24LE;
+                       break;
+               case 32:
+                       dsp_format = DSP_AUDIOFORM_SUPER_INTERLEAVE_32LE;
+                       break;
+               }
+               dsp_format |= format->interleave;
+       } else if (format->data_are_bigendian) {
+               /* For big-endian data, only 32 bit samples are supported */
+               switch (format->interleave) {
+               case 1:
+                       dsp_format = DSP_AUDIOFORM_MM_32BE;
+                       break;
+#ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+               case 2:
+                       dsp_format = DSP_AUDIOFORM_SS_32BE;
+                       break;
+#endif
+               }
+       } else if (format->interleave == 1 &&
+                  format->bits_per_sample == 32 && !format->mono_to_stereo) {
+               /* 32 bit little-endian mono->mono case */
+               dsp_format = DSP_AUDIOFORM_MM_32LE;
+       } else {
+               /* Handle the other little-endian formats */
+               switch (format->bits_per_sample) {
+               case 8:
+                       if (format->interleave == 2)
+                               dsp_format = DSP_AUDIOFORM_SS_8;
+                       else
+                               dsp_format = DSP_AUDIOFORM_MS_8;
+                       break;
+               default:
+               case 16:
+                       if (format->interleave == 2)
+                               dsp_format = DSP_AUDIOFORM_SS_16LE;
+                       else
+                               dsp_format = DSP_AUDIOFORM_MS_16LE;
+                       break;
+               case 24:
+                       if (format->interleave == 2)
+                               dsp_format = DSP_AUDIOFORM_SS_24LE;
+                       else
+                               dsp_format = DSP_AUDIOFORM_MS_24LE;
+                       break;
+               case 32:
+                       if (format->interleave == 2)
+                               dsp_format = DSP_AUDIOFORM_SS_32LE;
+                       else
+                               dsp_format = DSP_AUDIOFORM_MS_32LE;
+                       break;
+               }
+       }
+       DE_ACT(("set_audio_format[%d] = %x\n", pipe_index, dsp_format));
+       chip->comm_page->audio_format[pipe_index] = cpu_to_le16(dsp_format);
+}
+
+
+
+/* start_transport starts transport for a set of pipes.
+The bits 1 in channel_mask specify what pipes to start. Only the bit of the
+first channel must be set, regardless its interleave.
+Same thing for pause_ and stop_ -trasport below. */
+static int start_transport(struct echoaudio *chip, u32 channel_mask,
+                          u32 cyclic_mask)
+{
+       DE_ACT(("start_transport %x\n", channel_mask));
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->comm_page->cmd_start |= cpu_to_le32(channel_mask);
+
+       if (chip->comm_page->cmd_start) {
+               clear_handshake(chip);
+               send_vector(chip, DSP_VC_START_TRANSFER);
+               if (wait_handshake(chip))
+                       return -EIO;
+               /* Keep track of which pipes are transporting */
+               chip->active_mask |= channel_mask;
+               chip->comm_page->cmd_start = 0;
+               return 0;
+       }
+
+       DE_ACT(("start_transport: No pipes to start!\n"));
+       return -EINVAL;
+}
+
+
+
+static int pause_transport(struct echoaudio *chip, u32 channel_mask)
+{
+       DE_ACT(("pause_transport %x\n", channel_mask));
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->comm_page->cmd_stop |= cpu_to_le32(channel_mask);
+       chip->comm_page->cmd_reset = 0;
+       if (chip->comm_page->cmd_stop) {
+               clear_handshake(chip);
+               send_vector(chip, DSP_VC_STOP_TRANSFER);
+               if (wait_handshake(chip))
+                       return -EIO;
+               /* Keep track of which pipes are transporting */
+               chip->active_mask &= ~channel_mask;
+               chip->comm_page->cmd_stop = 0;
+               chip->comm_page->cmd_reset = 0;
+               return 0;
+       }
+
+       DE_ACT(("pause_transport: No pipes to stop!\n"));
+       return 0;
+}
+
+
+
+static int stop_transport(struct echoaudio *chip, u32 channel_mask)
+{
+       DE_ACT(("stop_transport %x\n", channel_mask));
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->comm_page->cmd_stop |= cpu_to_le32(channel_mask);
+       chip->comm_page->cmd_reset |= cpu_to_le32(channel_mask);
+       if (chip->comm_page->cmd_reset) {
+               clear_handshake(chip);
+               send_vector(chip, DSP_VC_STOP_TRANSFER);
+               if (wait_handshake(chip))
+                       return -EIO;
+               /* Keep track of which pipes are transporting */
+               chip->active_mask &= ~channel_mask;
+               chip->comm_page->cmd_stop = 0;
+               chip->comm_page->cmd_reset = 0;
+               return 0;
+       }
+
+       DE_ACT(("stop_transport: No pipes to stop!\n"));
+       return 0;
+}
+
+
+
+static inline int is_pipe_allocated(struct echoaudio *chip, u16 pipe_index)
+{
+       return (chip->pipe_alloc_mask & (1 << pipe_index));
+}
+
+
+
+/* Stops everything and turns off the DSP. All pipes should be already
+stopped and unallocated. */
+static int rest_in_peace(struct echoaudio *chip)
+{
+       DE_ACT(("rest_in_peace() open=%x\n", chip->pipe_alloc_mask));
+
+       /* Stops all active pipes (just to be sure) */
+       stop_transport(chip, chip->active_mask);
+
+       set_meters_on(chip, FALSE);
+
+#ifdef ECHOCARD_HAS_MIDI
+       enable_midi_input(chip, FALSE);
+#endif
+
+       /* Go to sleep */
+       if (chip->dsp_code) {
+               /* Make load_firmware do a complete reload */
+               chip->dsp_code = NULL;
+               /* Put the DSP to sleep */
+               return send_vector(chip, DSP_VC_GO_COMATOSE);
+       }
+       return 0;
+}
+
+
+
+/* Fills the comm page with default values */
+static int init_dsp_comm_page(struct echoaudio *chip)
+{
+       /* Check if the compiler added extra padding inside the structure */
+       if (offsetof(struct comm_page, midi_output) != 0xbe0) {
+               DE_INIT(("init_dsp_comm_page() - Invalid struct comm_page structure\n"));
+               return -EPERM;
+       }
+
+       /* Init all the basic stuff */
+       chip->card_name = ECHOCARD_NAME;
+       chip->bad_board = TRUE; /* Set TRUE until DSP loaded */
+       chip->dsp_code = NULL;  /* Current DSP code not loaded */
+       chip->digital_mode = DIGITAL_MODE_NONE;
+       chip->input_clock = ECHO_CLOCK_INTERNAL;
+       chip->output_clock = ECHO_CLOCK_WORD;
+       chip->asic_loaded = FALSE;
+       memset(chip->comm_page, 0, sizeof(struct comm_page));
+
+       /* Init the comm page */
+       chip->comm_page->comm_size =
+               __constant_cpu_to_le32(sizeof(struct comm_page));
+       chip->comm_page->handshake = 0xffffffff;
+       chip->comm_page->midi_out_free_count =
+               __constant_cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE);
+       chip->comm_page->sample_rate = __constant_cpu_to_le32(44100);
+       chip->sample_rate = 44100;
+
+       /* Set line levels so we don't blast any inputs on startup */
+       memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE);
+       memset(chip->comm_page->vmixer, ECHOGAIN_MUTED, VMIXER_ARRAY_SIZE);
+
+       return 0;
+}
+
+
+
+/* This function initializes the several volume controls for busses and pipes.
+This MUST be called after the DSP is up and running ! */
+static int init_line_levels(struct echoaudio *chip)
+{
+       int st, i, o;
+
+       DE_INIT(("init_line_levels\n"));
+
+       /* Mute output busses */
+       for (i = 0; i < num_busses_out(chip); i++)
+               if ((st = set_output_gain(chip, i, ECHOGAIN_MUTED)))
+                       return st;
+       if ((st = update_output_line_level(chip)))
+               return st;
+
+#ifdef ECHOCARD_HAS_VMIXER
+       /* Mute the Vmixer */
+       for (i = 0; i < num_pipes_out(chip); i++)
+               for (o = 0; o < num_busses_out(chip); o++)
+                       if ((st = set_vmixer_gain(chip, o, i, ECHOGAIN_MUTED)))
+                               return st;
+       if ((st = update_vmixer_level(chip)))
+               return st;
+#endif /* ECHOCARD_HAS_VMIXER */
+
+#ifdef ECHOCARD_HAS_MONITOR
+       /* Mute the monitor mixer */
+       for (o = 0; o < num_busses_out(chip); o++)
+               for (i = 0; i < num_busses_in(chip); i++)
+                       if ((st = set_monitor_gain(chip, o, i, ECHOGAIN_MUTED)))
+                               return st;
+       if ((st = update_output_line_level(chip)))
+               return st;
+#endif /* ECHOCARD_HAS_MONITOR */
+
+#ifdef ECHOCARD_HAS_INPUT_GAIN
+       for (i = 0; i < num_busses_in(chip); i++)
+               if ((st = set_input_gain(chip, i, ECHOGAIN_MUTED)))
+                       return st;
+       if ((st = update_input_line_level(chip)))
+               return st;
+#endif /* ECHOCARD_HAS_INPUT_GAIN */
+
+       return 0;
+}
+
+
+
+/* This is low level part of the interrupt handler.
+It returns -1 if the IRQ is not ours, or N>=0 if it is, where N is the number
+of midi data in the input queue. */
+static int service_irq(struct echoaudio *chip)
+{
+       int st;
+
+       /* Read the DSP status register and see if this DSP generated this interrupt */
+       if (get_dsp_register(chip, CHI32_STATUS_REG) & CHI32_STATUS_IRQ) {
+               st = 0;
+#ifdef ECHOCARD_HAS_MIDI
+               /* Get and parse midi data if present */
+               if (chip->comm_page->midi_input[0])     /* The count is at index 0 */
+                       st = midi_service_irq(chip);    /* Returns how many midi bytes we received */
+#endif
+               /* Clear the hardware interrupt */
+               chip->comm_page->midi_input[0] = 0;
+               send_vector(chip, DSP_VC_ACK_INT);
+               return st;
+       }
+       return -1;
+}
+
+
+
+
+/******************************************************************************
+       Functions for opening and closing pipes
+ ******************************************************************************/
+
+/* allocate_pipes is used to reserve audio pipes for your exclusive use.
+The call will fail if some pipes are already allocated. */
+static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
+                         int pipe_index, int interleave)
+{
+       int i;
+       u32 channel_mask;
+       char is_cyclic;
+
+       DE_ACT(("allocate_pipes: ch=%d int=%d\n", pipe_index, interleave));
+
+       if (chip->bad_board)
+               return -EIO;
+
+       is_cyclic = 1;  /* This driver uses cyclic buffers only */
+
+       for (channel_mask = i = 0; i < interleave; i++)
+               channel_mask |= 1 << (pipe_index + i);
+       if (chip->pipe_alloc_mask & channel_mask) {
+               DE_ACT(("allocate_pipes: channel already open\n"));
+               return -EAGAIN;
+       }
+
+       chip->comm_page->position[pipe_index] = 0;
+       chip->pipe_alloc_mask |= channel_mask;
+       if (is_cyclic)
+               chip->pipe_cyclic_mask |= channel_mask;
+       pipe->index = pipe_index;
+       pipe->interleave = interleave;
+       pipe->state = PIPE_STATE_STOPPED;
+
+       /* The counter register is where the DSP writes the 32 bit DMA
+       position for a pipe.  The DSP is constantly updating this value as
+       it moves data. The DMA counter is in units of bytes, not samples. */
+       pipe->dma_counter = &chip->comm_page->position[pipe_index];
+       *pipe->dma_counter = 0;
+       DE_ACT(("allocate_pipes: ok\n"));
+       return pipe_index;
+}
+
+
+
+static int free_pipes(struct echoaudio *chip, struct audiopipe *pipe)
+{
+       u32 channel_mask;
+       int i;
+
+       DE_ACT(("free_pipes: Pipe %d\n", pipe->index));
+       snd_assert(is_pipe_allocated(chip, pipe->index), return -EINVAL);
+       snd_assert(pipe->state == PIPE_STATE_STOPPED, return -EINVAL);
+
+       for (channel_mask = i = 0; i < pipe->interleave; i++)
+               channel_mask |= 1 << (pipe->index + i);
+
+       chip->pipe_alloc_mask &= ~channel_mask;
+       chip->pipe_cyclic_mask &= ~channel_mask;
+       return 0;
+}
+
+
+
+/******************************************************************************
+       Functions for managing the scatter-gather list
+******************************************************************************/
+
+static int sglist_init(struct echoaudio *chip, struct audiopipe *pipe)
+{
+       pipe->sglist_head = 0;
+       memset(pipe->sgpage.area, 0, PAGE_SIZE);
+       chip->comm_page->sglist_addr[pipe->index].addr =
+               cpu_to_le32(pipe->sgpage.addr);
+       return 0;
+}
+
+
+
+static int sglist_add_mapping(struct echoaudio *chip, struct audiopipe *pipe,
+                               dma_addr_t address, size_t length)
+{
+       int head = pipe->sglist_head;
+       struct sg_entry *list = (struct sg_entry *)pipe->sgpage.area;
+
+       if (head < MAX_SGLIST_ENTRIES - 1) {
+               list[head].addr = cpu_to_le32(address);
+               list[head].size = cpu_to_le32(length);
+               pipe->sglist_head++;
+       } else {
+               DE_ACT(("SGlist: too many fragments\n"));
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+
+
+static inline int sglist_add_irq(struct echoaudio *chip, struct audiopipe *pipe)
+{
+       return sglist_add_mapping(chip, pipe, 0, 0);
+}
+
+
+
+static inline int sglist_wrap(struct echoaudio *chip, struct audiopipe *pipe)
+{
+       return sglist_add_mapping(chip, pipe, pipe->sgpage.addr, 0);
+}
diff --git a/sound/pci/echoaudio/echoaudio_dsp.h b/sound/pci/echoaudio/echoaudio_dsp.h
new file mode 100644 (file)
index 0000000..e55ee00
--- /dev/null
@@ -0,0 +1,694 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+#ifndef _ECHO_DSP_
+#define _ECHO_DSP_
+
+
+/**** Echogals: Darla20, Gina20, Layla20, and Darla24 ****/
+#if defined(ECHOGALS_FAMILY)
+
+#define NUM_ASIC_TESTS         5
+#define READ_DSP_TIMEOUT       1000000L        /* one second */
+
+/**** Echo24: Gina24, Layla24, Mona, Mia, Mia-midi ****/
+#elif defined(ECHO24_FAMILY)
+
+#define DSP_56361                      /* Some Echo24 cards use the 56361 DSP */
+#define READ_DSP_TIMEOUT       100000L         /* .1 second */
+
+/**** 3G: Gina3G, Layla3G ****/
+#elif defined(ECHO3G_FAMILY)
+
+#define DSP_56361
+#define READ_DSP_TIMEOUT       100000L         /* .1 second */
+#define MIN_MTC_1X_RATE                32000
+
+/**** Indigo: Indigo, Indigo IO, Indigo DJ ****/
+#elif defined(INDIGO_FAMILY)
+
+#define DSP_56361
+#define READ_DSP_TIMEOUT       100000L         /* .1 second */
+
+#else
+
+#error No family is defined
+
+#endif
+
+
+
+/*
+ *
+ *  Max inputs and outputs
+ *
+ */
+
+#define DSP_MAXAUDIOINPUTS             16      /* Max audio input channels */
+#define DSP_MAXAUDIOOUTPUTS            16      /* Max audio output channels */
+#define DSP_MAXPIPES                   32      /* Max total pipes (input + output) */
+
+
+/*
+ *
+ * These are the offsets for the memory-mapped DSP registers; the DSP base
+ * address is treated as the start of a u32 array.
+ */
+
+#define CHI32_CONTROL_REG              4
+#define CHI32_STATUS_REG               5
+#define CHI32_VECTOR_REG               6
+#define CHI32_DATA_REG                 7
+
+
+/*
+ *
+ * Interesting bits within the DSP registers
+ *
+ */
+
+#define CHI32_VECTOR_BUSY              0x00000001
+#define CHI32_STATUS_REG_HF3           0x00000008
+#define CHI32_STATUS_REG_HF4           0x00000010
+#define CHI32_STATUS_REG_HF5           0x00000020
+#define CHI32_STATUS_HOST_READ_FULL    0x00000004
+#define CHI32_STATUS_HOST_WRITE_EMPTY  0x00000002
+#define CHI32_STATUS_IRQ               0x00000040
+
+
+/* 
+ *
+ * DSP commands sent via slave mode; these are sent to the DSP by write_dsp()
+ *
+ */
+
+#define DSP_FNC_SET_COMMPAGE_ADDR              0x02
+#define DSP_FNC_LOAD_LAYLA_ASIC                        0xa0
+#define DSP_FNC_LOAD_GINA24_ASIC               0xa0
+#define DSP_FNC_LOAD_MONA_PCI_CARD_ASIC                0xa0
+#define DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC     0xa0
+#define DSP_FNC_LOAD_MONA_EXTERNAL_ASIC                0xa1
+#define DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC     0xa1
+#define DSP_FNC_LOAD_3G_ASIC                   0xa0
+
+
+/*
+ *
+ * Defines to handle the MIDI input state engine; these are used to properly
+ * extract MIDI time code bytes and their timestamps from the MIDI input stream.
+ *
+ */
+
+#define MIDI_IN_STATE_NORMAL   0
+#define MIDI_IN_STATE_TS_HIGH  1
+#define MIDI_IN_STATE_TS_LOW   2
+#define MIDI_IN_STATE_F1_DATA  3
+#define MIDI_IN_SKIP_DATA      (-1)
+
+
+/*----------------------------------------------------------------------------
+
+Setting the sample rates on Layla24 is somewhat schizophrenic.
+
+For standard rates, it works exactly like Mona and Gina24.  That is, for
+8, 11.025, 16, 22.05, 32, 44.1, 48, 88.2, and 96 kHz, you just set the
+appropriate bits in the control register and write the control register.
+
+In order to support MIDI time code sync (and possibly SMPTE LTC sync in
+the future), Layla24 also has "continuous sample rate mode".  In this mode,
+Layla24 can generate any sample rate between 25 and 50 kHz inclusive, or
+50 to 100 kHz inclusive for double speed mode.
+
+To use continuous mode:
+
+-Set the clock select bits in the control register to 0xe (see the #define
+ below)
+
+-Set double-speed mode if you want to use sample rates above 50 kHz
+
+-Write the control register as you would normally
+
+-Now, you need to set the frequency register. First, you need to determine the
+ value for the frequency register.  This is given by the following formula:
+
+frequency_reg = (LAYLA24_MAGIC_NUMBER / sample_rate) - 2
+
+Note the #define below for the magic number
+
+-Wait for the DSP handshake
+-Write the frequency_reg value to the .SampleRate field of the comm page
+-Send the vector command SET_LAYLA24_FREQUENCY_REG (see vmonkey.h)
+
+Once you have set the control register up for continuous mode, you can just
+write the frequency register to change the sample rate.  This could be
+used for MIDI time code sync. For MTC sync, the control register is set for
+continuous mode.  The driver then just keeps writing the
+SET_LAYLA24_FREQUENCY_REG command.
+
+-----------------------------------------------------------------------------*/
+
+#define LAYLA24_MAGIC_NUMBER                   677376000
+#define LAYLA24_CONTINUOUS_CLOCK               0x000e
+
+
+/*
+ *
+ * DSP vector commands
+ *
+ */
+
+#define DSP_VC_RESET                           0x80ff
+
+#ifndef DSP_56361
+
+#define DSP_VC_ACK_INT                         0x8073
+#define DSP_VC_SET_VMIXER_GAIN                 0x0000  /* Not used, only for compile */
+#define DSP_VC_START_TRANSFER                  0x0075  /* Handshke rqd. */
+#define DSP_VC_METERS_ON                       0x0079
+#define DSP_VC_METERS_OFF                      0x007b
+#define DSP_VC_UPDATE_OUTVOL                   0x007d  /* Handshke rqd. */
+#define DSP_VC_UPDATE_INGAIN                   0x007f  /* Handshke rqd. */
+#define DSP_VC_ADD_AUDIO_BUFFER                        0x0081  /* Handshke rqd. */
+#define DSP_VC_TEST_ASIC                       0x00eb
+#define DSP_VC_UPDATE_CLOCKS                   0x00ef  /* Handshke rqd. */
+#define DSP_VC_SET_LAYLA_SAMPLE_RATE           0x00f1  /* Handshke rqd. */
+#define DSP_VC_SET_GD_AUDIO_STATE              0x00f1  /* Handshke rqd. */
+#define DSP_VC_WRITE_CONTROL_REG               0x00f1  /* Handshke rqd. */
+#define DSP_VC_MIDI_WRITE                      0x00f5  /* Handshke rqd. */
+#define DSP_VC_STOP_TRANSFER                   0x00f7  /* Handshke rqd. */
+#define DSP_VC_UPDATE_FLAGS                    0x00fd  /* Handshke rqd. */
+#define DSP_VC_GO_COMATOSE                     0x00f9
+
+#else /* !DSP_56361 */
+
+/* Vector commands for families that use either the 56301 or 56361 */
+#define DSP_VC_ACK_INT                         0x80F5
+#define DSP_VC_SET_VMIXER_GAIN                 0x00DB  /* Handshke rqd. */
+#define DSP_VC_START_TRANSFER                  0x00DD  /* Handshke rqd. */
+#define DSP_VC_METERS_ON                       0x00EF
+#define DSP_VC_METERS_OFF                      0x00F1
+#define DSP_VC_UPDATE_OUTVOL                   0x00E3  /* Handshke rqd. */
+#define DSP_VC_UPDATE_INGAIN                   0x00E5  /* Handshke rqd. */
+#define DSP_VC_ADD_AUDIO_BUFFER                        0x00E1  /* Handshke rqd. */
+#define DSP_VC_TEST_ASIC                       0x00ED
+#define DSP_VC_UPDATE_CLOCKS                   0x00E9  /* Handshke rqd. */
+#define DSP_VC_SET_LAYLA24_FREQUENCY_REG       0x00E9  /* Handshke rqd. */
+#define DSP_VC_SET_LAYLA_SAMPLE_RATE           0x00EB  /* Handshke rqd. */
+#define DSP_VC_SET_GD_AUDIO_STATE              0x00EB  /* Handshke rqd. */
+#define DSP_VC_WRITE_CONTROL_REG               0x00EB  /* Handshke rqd. */
+#define DSP_VC_MIDI_WRITE                      0x00E7  /* Handshke rqd. */
+#define DSP_VC_STOP_TRANSFER                   0x00DF  /* Handshke rqd. */
+#define DSP_VC_UPDATE_FLAGS                    0x00FB  /* Handshke rqd. */
+#define DSP_VC_GO_COMATOSE                     0x00d9
+
+#endif /* !DSP_56361 */
+
+
+/*
+ *
+ * Timeouts
+ *
+ */
+
+#define HANDSHAKE_TIMEOUT              20000   /* send_vector command timeout (20ms) */
+#define VECTOR_BUSY_TIMEOUT            100000  /* 100ms */
+#define MIDI_OUT_DELAY_USEC            2000    /* How long to wait after MIDI fills up */
+
+
+/*
+ *
+ * Flags for .Flags field in the comm page
+ *
+ */
+
+#define DSP_FLAG_MIDI_INPUT            0x0001  /* Enable MIDI input */
+#define DSP_FLAG_SPDIF_NONAUDIO                0x0002  /* Sets the "non-audio" bit
+                                                * in the S/PDIF out status
+                                                * bits.  Clear this flag for
+                                                * audio data;
+                                                * set it for AC3 or WMA or
+                                                * some such */
+#define DSP_FLAG_PROFESSIONAL_SPDIF    0x0008  /* 1 Professional, 0 Consumer */
+
+
+/*
+ *
+ * Clock detect bits reported by the DSP for Gina20, Layla20, Darla24, and Mia
+ *
+ */
+
+#define GLDM_CLOCK_DETECT_BIT_WORD     0x0002
+#define GLDM_CLOCK_DETECT_BIT_SUPER    0x0004
+#define GLDM_CLOCK_DETECT_BIT_SPDIF    0x0008
+#define GLDM_CLOCK_DETECT_BIT_ESYNC    0x0010
+
+
+/*
+ *
+ * Clock detect bits reported by the DSP for Gina24, Mona, and Layla24
+ *
+ */
+
+#define GML_CLOCK_DETECT_BIT_WORD96    0x0002
+#define GML_CLOCK_DETECT_BIT_WORD48    0x0004
+#define GML_CLOCK_DETECT_BIT_SPDIF48   0x0008
+#define GML_CLOCK_DETECT_BIT_SPDIF96   0x0010
+#define GML_CLOCK_DETECT_BIT_WORD      (GML_CLOCK_DETECT_BIT_WORD96 | GML_CLOCK_DETECT_BIT_WORD48)
+#define GML_CLOCK_DETECT_BIT_SPDIF     (GML_CLOCK_DETECT_BIT_SPDIF48 | GML_CLOCK_DETECT_BIT_SPDIF96)
+#define GML_CLOCK_DETECT_BIT_ESYNC     0x0020
+#define GML_CLOCK_DETECT_BIT_ADAT      0x0040
+
+
+/*
+ *
+ * Layla clock numbers to send to DSP
+ *
+ */
+
+#define LAYLA20_CLOCK_INTERNAL         0
+#define LAYLA20_CLOCK_SPDIF            1
+#define LAYLA20_CLOCK_WORD             2
+#define LAYLA20_CLOCK_SUPER            3
+
+
+/*
+ *
+ * Gina/Darla clock states
+ *
+ */
+
+#define GD_CLOCK_NOCHANGE              0
+#define GD_CLOCK_44                    1
+#define GD_CLOCK_48                    2
+#define GD_CLOCK_SPDIFIN               3
+#define GD_CLOCK_UNDEF                 0xff
+
+
+/*
+ *
+ * Gina/Darla S/PDIF status bits
+ *
+ */
+
+#define GD_SPDIF_STATUS_NOCHANGE       0
+#define GD_SPDIF_STATUS_44             1
+#define GD_SPDIF_STATUS_48             2
+#define GD_SPDIF_STATUS_UNDEF          0xff
+
+
+/*
+ *
+ * Layla20 output clocks
+ *
+ */
+
+#define LAYLA20_OUTPUT_CLOCK_SUPER     0
+#define LAYLA20_OUTPUT_CLOCK_WORD      1
+
+
+/****************************************************************************
+
+   Magic constants for the Darla24 hardware
+
+ ****************************************************************************/
+
+#define GD24_96000     0x0
+#define GD24_48000     0x1
+#define GD24_44100     0x2
+#define GD24_32000     0x3
+#define GD24_22050     0x4
+#define GD24_16000     0x5
+#define GD24_11025     0x6
+#define GD24_8000      0x7
+#define GD24_88200     0x8
+#define GD24_EXT_SYNC  0x9
+
+
+/*
+ *
+ * Return values from the DSP when ASIC is loaded
+ *
+ */
+
+#define ASIC_ALREADY_LOADED    0x1
+#define ASIC_NOT_LOADED                0x0
+
+
+/*
+ *
+ * DSP Audio formats
+ *
+ * These are the audio formats that the DSP can transfer
+ * via input and output pipes.  LE means little-endian,
+ * BE means big-endian.
+ *
+ * DSP_AUDIOFORM_MS_8   
+ *
+ *    8-bit mono unsigned samples.  For playback,
+ *    mono data is duplicated out the left and right channels
+ *    of the output bus.  The "MS" part of the name
+ *    means mono->stereo.
+ *
+ * DSP_AUDIOFORM_MS_16LE
+ *
+ *    16-bit signed little-endian mono samples.  Playback works
+ *    like the previous code.
+ *
+ * DSP_AUDIOFORM_MS_24LE
+ *
+ *    24-bit signed little-endian mono samples.  Data is packed
+ *    three bytes per sample; if you had two samples 0x112233 and 0x445566
+ *    they would be stored in memory like this: 33 22 11 66 55 44.
+ *
+ * DSP_AUDIOFORM_MS_32LE
+ * 
+ *    24-bit signed little-endian mono samples in a 32-bit 
+ *    container.  In other words, each sample is a 32-bit signed 
+ *    integer, where the actual audio data is left-justified 
+ *    in the 32 bits and only the 24 most significant bits are valid.
+ *
+ * DSP_AUDIOFORM_SS_8
+ * DSP_AUDIOFORM_SS_16LE
+ * DSP_AUDIOFORM_SS_24LE
+ * DSP_AUDIOFORM_SS_32LE
+ *
+ *    Like the previous ones, except now with stereo interleaved
+ *    data.  "SS" means stereo->stereo.
+ *
+ * DSP_AUDIOFORM_MM_32LE
+ *
+ *    Similar to DSP_AUDIOFORM_MS_32LE, except that the mono
+ *    data is not duplicated out both the left and right outputs.
+ *    This mode is used by the ASIO driver.  Here, "MM" means
+ *    mono->mono.
+ *
+ * DSP_AUDIOFORM_MM_32BE
+ *
+ *    Just like DSP_AUDIOFORM_MM_32LE, but now the data is
+ *    in big-endian format.
+ *
+ */
+
+#define DSP_AUDIOFORM_MS_8     0       /* 8 bit mono */
+#define DSP_AUDIOFORM_MS_16LE  1       /* 16 bit mono */
+#define DSP_AUDIOFORM_MS_24LE  2       /* 24 bit mono */
+#define DSP_AUDIOFORM_MS_32LE  3       /* 32 bit mono */
+#define DSP_AUDIOFORM_SS_8     4       /* 8 bit stereo */
+#define DSP_AUDIOFORM_SS_16LE  5       /* 16 bit stereo */
+#define DSP_AUDIOFORM_SS_24LE  6       /* 24 bit stereo */
+#define DSP_AUDIOFORM_SS_32LE  7       /* 32 bit stereo */
+#define DSP_AUDIOFORM_MM_32LE  8       /* 32 bit mono->mono little-endian */
+#define DSP_AUDIOFORM_MM_32BE  9       /* 32 bit mono->mono big-endian */
+#define DSP_AUDIOFORM_SS_32BE  10      /* 32 bit stereo big endian */
+#define DSP_AUDIOFORM_INVALID  0xFF    /* Invalid audio format */
+
+
+/*
+ *
+ * Super-interleave is defined as interleaving by 4 or more.  Darla20 and Gina20
+ * do not support super interleave.
+ *
+ * 16 bit, 24 bit, and 32 bit little endian samples are supported for super 
+ * interleave.  The interleave factor must be even.  16 - way interleave is the 
+ * current maximum, so you can interleave by 4, 6, 8, 10, 12, 14, and 16.
+ *
+ * The actual format code is derived by taking the define below and or-ing with
+ * the interleave factor.  So, 32 bit interleave by 6 is 0x86 and
+ * 16 bit interleave by 16 is (0x40 | 0x10) = 0x50.
+ *
+ */
+
+#define DSP_AUDIOFORM_SUPER_INTERLEAVE_16LE    0x40
+#define DSP_AUDIOFORM_SUPER_INTERLEAVE_24LE    0xc0
+#define DSP_AUDIOFORM_SUPER_INTERLEAVE_32LE    0x80
+
+
+/*
+ *
+ * Gina24, Mona, and Layla24 control register defines
+ *
+ */
+
+#define GML_CONVERTER_ENABLE   0x0010
+#define GML_SPDIF_PRO_MODE     0x0020  /* Professional S/PDIF == 1,
+                                          consumer == 0 */
+#define GML_SPDIF_SAMPLE_RATE0 0x0040
+#define GML_SPDIF_SAMPLE_RATE1 0x0080
+#define GML_SPDIF_TWO_CHANNEL  0x0100  /* 1 == two channels,
+                                          0 == one channel */
+#define GML_SPDIF_NOT_AUDIO    0x0200
+#define GML_SPDIF_COPY_PERMIT  0x0400
+#define GML_SPDIF_24_BIT       0x0800  /* 1 == 24 bit, 0 == 20 bit */
+#define GML_ADAT_MODE          0x1000  /* 1 == ADAT mode, 0 == S/PDIF mode */
+#define GML_SPDIF_OPTICAL_MODE 0x2000  /* 1 == optical mode, 0 == RCA mode */
+#define GML_SPDIF_CDROM_MODE   0x3000  /* 1 == CDROM mode,
+                                        * 0 == RCA or optical mode */
+#define GML_DOUBLE_SPEED_MODE  0x4000  /* 1 == double speed,
+                                          0 == single speed */
+
+#define GML_DIGITAL_IN_AUTO_MUTE 0x800000
+
+#define GML_96KHZ              (0x0 | GML_DOUBLE_SPEED_MODE)
+#define GML_88KHZ              (0x1 | GML_DOUBLE_SPEED_MODE)
+#define GML_48KHZ              0x2
+#define GML_44KHZ              0x3
+#define GML_32KHZ              0x4
+#define GML_22KHZ              0x5
+#define GML_16KHZ              0x6
+#define GML_11KHZ              0x7
+#define GML_8KHZ               0x8
+#define GML_SPDIF_CLOCK                0x9
+#define GML_ADAT_CLOCK         0xA
+#define GML_WORD_CLOCK         0xB
+#define GML_ESYNC_CLOCK                0xC
+#define GML_ESYNCx2_CLOCK      0xD
+
+#define GML_CLOCK_CLEAR_MASK           0xffffbff0
+#define GML_SPDIF_RATE_CLEAR_MASK      (~(GML_SPDIF_SAMPLE_RATE0|GML_SPDIF_SAMPLE_RATE1))
+#define GML_DIGITAL_MODE_CLEAR_MASK    0xffffcfff
+#define GML_SPDIF_FORMAT_CLEAR_MASK    0xfffff01f
+
+
+/*
+ *
+ * Mia sample rate and clock setting constants
+ *
+ */
+
+#define MIA_32000      0x0040
+#define MIA_44100      0x0042
+#define MIA_48000      0x0041
+#define MIA_88200      0x0142
+#define MIA_96000      0x0141
+
+#define MIA_SPDIF      0x00000044
+#define MIA_SPDIF96    0x00000144
+
+#define MIA_MIDI_REV   1       /* Must be Mia rev 1 for MIDI support */
+
+
+/*
+ *
+ * 3G register bits
+ *
+ */
+
+#define E3G_CONVERTER_ENABLE   0x0010
+#define E3G_SPDIF_PRO_MODE     0x0020  /* Professional S/PDIF == 1,
+                                          consumer == 0 */
+#define E3G_SPDIF_SAMPLE_RATE0 0x0040
+#define E3G_SPDIF_SAMPLE_RATE1 0x0080
+#define E3G_SPDIF_TWO_CHANNEL  0x0100  /* 1 == two channels,
+                                          0 == one channel */
+#define E3G_SPDIF_NOT_AUDIO    0x0200
+#define E3G_SPDIF_COPY_PERMIT  0x0400
+#define E3G_SPDIF_24_BIT       0x0800  /* 1 == 24 bit, 0 == 20 bit */
+#define E3G_DOUBLE_SPEED_MODE  0x4000  /* 1 == double speed,
+                                          0 == single speed */
+#define E3G_PHANTOM_POWER      0x8000  /* 1 == phantom power on,
+                                          0 == phantom power off */
+
+#define E3G_96KHZ              (0x0 | E3G_DOUBLE_SPEED_MODE)
+#define E3G_88KHZ              (0x1 | E3G_DOUBLE_SPEED_MODE)
+#define E3G_48KHZ              0x2
+#define E3G_44KHZ              0x3
+#define E3G_32KHZ              0x4
+#define E3G_22KHZ              0x5
+#define E3G_16KHZ              0x6
+#define E3G_11KHZ              0x7
+#define E3G_8KHZ               0x8
+#define E3G_SPDIF_CLOCK                0x9
+#define E3G_ADAT_CLOCK         0xA
+#define E3G_WORD_CLOCK         0xB
+#define E3G_CONTINUOUS_CLOCK   0xE
+
+#define E3G_ADAT_MODE          0x1000
+#define E3G_SPDIF_OPTICAL_MODE 0x2000
+
+#define E3G_CLOCK_CLEAR_MASK           0xbfffbff0
+#define E3G_DIGITAL_MODE_CLEAR_MASK    0xffffcfff
+#define E3G_SPDIF_FORMAT_CLEAR_MASK    0xfffff01f
+
+/* Clock detect bits reported by the DSP */
+#define E3G_CLOCK_DETECT_BIT_WORD96    0x0001
+#define E3G_CLOCK_DETECT_BIT_WORD48    0x0002
+#define E3G_CLOCK_DETECT_BIT_SPDIF48   0x0004
+#define E3G_CLOCK_DETECT_BIT_ADAT      0x0004
+#define E3G_CLOCK_DETECT_BIT_SPDIF96   0x0008
+#define E3G_CLOCK_DETECT_BIT_WORD      (E3G_CLOCK_DETECT_BIT_WORD96|E3G_CLOCK_DETECT_BIT_WORD48)
+#define E3G_CLOCK_DETECT_BIT_SPDIF     (E3G_CLOCK_DETECT_BIT_SPDIF48|E3G_CLOCK_DETECT_BIT_SPDIF96)
+
+/* Frequency control register */
+#define E3G_MAGIC_NUMBER               677376000
+#define E3G_FREQ_REG_DEFAULT           (E3G_MAGIC_NUMBER / 48000 - 2)
+#define E3G_FREQ_REG_MAX               0xffff
+
+/* 3G external box types */
+#define E3G_GINA3G_BOX_TYPE            0x00
+#define E3G_LAYLA3G_BOX_TYPE           0x10
+#define E3G_ASIC_NOT_LOADED            0xffff
+#define E3G_BOX_TYPE_MASK              0xf0
+
+#define EXT_3GBOX_NC                   0x01
+#define EXT_3GBOX_NOT_SET              0x02
+
+
+/*
+ *
+ * Gina20 & Layla20 have input gain controls for the analog inputs;
+ * this is the magic number for the hardware that gives you 0 dB at -10.
+ *
+ */
+
+#define GL20_INPUT_GAIN_MAGIC_NUMBER   0xC8
+
+
+/*
+ *
+ * Defines how much time must pass between DSP load attempts
+ *
+ */
+
+#define DSP_LOAD_ATTEMPT_PERIOD                1000000L        /* One second */
+
+
+/*
+ *
+ * Size of arrays for the comm page.  MAX_PLAY_TAPS and MAX_REC_TAPS are
+ * no longer used, but the sizes must still be right for the DSP to see
+ * the comm page correctly.
+ *
+ */
+
+#define MONITOR_ARRAY_SIZE     0x180
+#define VMIXER_ARRAY_SIZE      0x40
+#define MIDI_OUT_BUFFER_SIZE   32
+#define MIDI_IN_BUFFER_SIZE    256
+#define MAX_PLAY_TAPS          168
+#define MAX_REC_TAPS           192
+#define DSP_MIDI_OUT_FIFO_SIZE 64
+
+
+/* sg_entry is a single entry for the scatter-gather list.  The array of struct
+sg_entry struct is read by the DSP, so all values must be little-endian. */
+
+#define MAX_SGLIST_ENTRIES 512
+
+struct sg_entry {
+       u32 addr;
+       u32 size;
+};
+
+
+/****************************************************************************
+
+  The comm page.  This structure is read and written by the DSP; the
+  DSP code is a firm believer in the byte offsets written in the comments
+  at the end of each line.  This structure should not be changed.
+
+  Any reads from or writes to this structure should be in little-endian format.
+
+ ****************************************************************************/
+
+struct comm_page {             /*                              Base    Length*/
+       u32 comm_size;          /* size of this object          0x000   4 */
+       u32 flags;              /* See Appendix A below         0x004   4 */
+       u32 unused;             /* Unused entry                 0x008   4 */
+       u32 sample_rate;        /* Card sample rate in Hz       0x00c   4 */
+       volatile u32 handshake; /* DSP command handshake        0x010   4 */
+       u32 cmd_start;          /* Chs. to start mask           0x014   4 */
+       u32 cmd_stop;           /* Chs. to stop mask            0x018   4 */
+       u32 cmd_reset;          /* Chs. to reset mask           0x01c   4 */
+       u16 audio_format[DSP_MAXPIPES]; /* Chs. audio format    0x020   32*2 */
+       struct sg_entry sglist_addr[DSP_MAXPIPES];
+                               /* Chs. Physical sglist addrs   0x060   32*8 */
+       volatile u32 position[DSP_MAXPIPES];
+                               /* Positions for ea. ch.        0x160   32*4 */
+       volatile s8 vu_meter[DSP_MAXPIPES];
+                               /* VU meters                    0x1e0   32*1 */
+       volatile s8 peak_meter[DSP_MAXPIPES];
+                               /* Peak meters                  0x200   32*1 */
+       s8 line_out_level[DSP_MAXAUDIOOUTPUTS];
+                               /* Output gain                  0x220   16*1 */
+       s8 line_in_level[DSP_MAXAUDIOINPUTS];
+                               /* Input gain                   0x230   16*1 */
+       s8 monitors[MONITOR_ARRAY_SIZE];
+                               /* Monitor map                  0x240   0x180 */
+       u32 play_coeff[MAX_PLAY_TAPS];
+                       /* Gina/Darla play filters - obsolete   0x3c0   168*4 */
+       u32 rec_coeff[MAX_REC_TAPS];
+                       /* Gina/Darla record filters - obsolete 0x660   192*4 */
+       volatile u16 midi_input[MIDI_IN_BUFFER_SIZE];
+                       /* MIDI input data transfer buffer      0x960   256*2 */
+       u8 gd_clock_state;      /* Chg Gina/Darla clock state   0xb60   1 */
+       u8 gd_spdif_status;     /* Chg. Gina/Darla S/PDIF state 0xb61   1 */
+       u8 gd_resampler_state;  /* Should always be 3           0xb62   1 */
+       u8 filler2;             /*                              0xb63   1 */
+       u32 nominal_level_mask; /* -10 level enable mask        0xb64   4 */
+       u16 input_clock;        /* Chg. Input clock state       0xb68   2 */
+       u16 output_clock;       /* Chg. Output clock state      0xb6a   2 */
+       volatile u32 status_clocks;
+                               /* Current Input clock state    0xb6c   4 */
+       u32 ext_box_status;     /* External box status          0xb70   4 */
+       u32 cmd_add_buffer;     /* Pipes to add (obsolete)      0xb74   4 */
+       volatile u32 midi_out_free_count;
+                       /* # of bytes free in MIDI output FIFO  0xb78   4 */
+       u32 unused2;            /* Cyclic pipes                 0xb7c   4 */
+       u32 control_register;
+                       /* Mona, Gina24, Layla24, 3G ctrl reg   0xb80   4 */
+       u32 e3g_frq_register;   /* 3G frequency register        0xb84   4 */
+       u8 filler[24];          /* filler                       0xb88   24*1 */
+       s8 vmixer[VMIXER_ARRAY_SIZE];
+                               /* Vmixer levels                0xba0   64*1 */
+       u8 midi_output[MIDI_OUT_BUFFER_SIZE];
+                               /* MIDI output data             0xbe0   32*1 */
+};
+
+#endif /* _ECHO_DSP_ */
diff --git a/sound/pci/echoaudio/echoaudio_gml.c b/sound/pci/echoaudio/echoaudio_gml.c
new file mode 100644 (file)
index 0000000..3aa37e7
--- /dev/null
@@ -0,0 +1,198 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+/* These functions are common for Gina24, Layla24 and Mona cards */
+
+
+/* ASIC status check - some cards have one or two ASICs that need to be
+loaded.  Once that load is complete, this function is called to see if
+the load was successful.
+If this load fails, it does not necessarily mean that the hardware is
+defective - the external box may be disconnected or turned off. */
+static int check_asic_status(struct echoaudio *chip)
+{
+       u32 asic_status;
+
+       send_vector(chip, DSP_VC_TEST_ASIC);
+
+       /* The DSP will return a value to indicate whether or not the
+          ASIC is currently loaded */
+       if (read_dsp(chip, &asic_status) < 0) {
+               DE_INIT(("check_asic_status: failed on read_dsp\n"));
+               chip->asic_loaded = FALSE;
+               return -EIO;
+       }
+
+       chip->asic_loaded = (asic_status == ASIC_ALREADY_LOADED);
+       return chip->asic_loaded ? 0 : -EIO;
+}
+
+
+
+/* Most configuration of Gina24, Layla24, or Mona is accomplished by writing
+the control register.  write_control_reg sends the new control register
+value to the DSP. */
+static int write_control_reg(struct echoaudio *chip, u32 value, char force)
+{
+       /* Handle the digital input auto-mute */
+       if (chip->digital_in_automute)
+               value |= GML_DIGITAL_IN_AUTO_MUTE;
+       else
+               value &= ~GML_DIGITAL_IN_AUTO_MUTE;
+
+       DE_ACT(("write_control_reg: 0x%x\n", value));
+
+       /* Write the control register */
+       value = cpu_to_le32(value);
+       if (value != chip->comm_page->control_register || force) {
+               if (wait_handshake(chip))
+                       return -EIO;
+               chip->comm_page->control_register = value;
+               clear_handshake(chip);
+               return send_vector(chip, DSP_VC_WRITE_CONTROL_REG);
+       }
+       return 0;
+}
+
+
+
+/* Gina24, Layla24, and Mona support digital input auto-mute.  If the digital
+input auto-mute is enabled, the DSP will only enable the digital inputs if
+the card is syncing to a valid clock on the ADAT or S/PDIF inputs.
+If the auto-mute is disabled, the digital inputs are enabled regardless of
+what the input clock is set or what is connected. */
+static int set_input_auto_mute(struct echoaudio *chip, int automute)
+{
+       DE_ACT(("set_input_auto_mute %d\n", automute));
+
+       chip->digital_in_automute = automute;
+
+       /* Re-set the input clock to the current value - indirectly causes
+       the auto-mute flag to be sent to the DSP */
+       return set_input_clock(chip, chip->input_clock);
+}
+
+
+
+/* S/PDIF coax / S/PDIF optical / ADAT - switch */
+static int set_digital_mode(struct echoaudio *chip, u8 mode)
+{
+       u8 previous_mode;
+       int err, i, o;
+
+       if (chip->bad_board)
+               return -EIO;
+
+       /* All audio channels must be closed before changing the digital mode */
+       snd_assert(!chip->pipe_alloc_mask, return -EAGAIN);
+
+       snd_assert(chip->digital_modes & (1 << mode), return -EINVAL);
+
+       previous_mode = chip->digital_mode;
+       err = dsp_set_digital_mode(chip, mode);
+
+       /* If we successfully changed the digital mode from or to ADAT,
+          then make sure all output, input and monitor levels are
+          updated by the DSP comm object. */
+       if (err >= 0 && previous_mode != mode &&
+           (previous_mode == DIGITAL_MODE_ADAT || mode == DIGITAL_MODE_ADAT)) {
+               spin_lock_irq(&chip->lock);
+               for (o = 0; o < num_busses_out(chip); o++)
+                       for (i = 0; i < num_busses_in(chip); i++)
+                               set_monitor_gain(chip, o, i,
+                                                chip->monitor_gain[o][i]);
+
+#ifdef ECHOCARD_HAS_INPUT_GAIN
+               for (i = 0; i < num_busses_in(chip); i++)
+                       set_input_gain(chip, i, chip->input_gain[i]);
+               update_input_line_level(chip);
+#endif
+
+               for (o = 0; o < num_busses_out(chip); o++)
+                       set_output_gain(chip, o, chip->output_gain[o]);
+               update_output_line_level(chip);
+               spin_unlock_irq(&chip->lock);
+       }
+
+       return err;
+}
+
+
+
+/* Set the S/PDIF output format */
+static int set_professional_spdif(struct echoaudio *chip, char prof)
+{
+       u32 control_reg;
+       int err;
+
+       /* Clear the current S/PDIF flags */
+       control_reg = le32_to_cpu(chip->comm_page->control_register);
+       control_reg &= GML_SPDIF_FORMAT_CLEAR_MASK;
+
+       /* Set the new S/PDIF flags depending on the mode */
+       control_reg |= GML_SPDIF_TWO_CHANNEL | GML_SPDIF_24_BIT |
+               GML_SPDIF_COPY_PERMIT;
+       if (prof) {
+               /* Professional mode */
+               control_reg |= GML_SPDIF_PRO_MODE;
+
+               switch (chip->sample_rate) {
+               case 32000:
+                       control_reg |= GML_SPDIF_SAMPLE_RATE0 |
+                               GML_SPDIF_SAMPLE_RATE1;
+                       break;
+               case 44100:
+                       control_reg |= GML_SPDIF_SAMPLE_RATE0;
+                       break;
+               case 48000:
+                       control_reg |= GML_SPDIF_SAMPLE_RATE1;
+                       break;
+               }
+       } else {
+               /* Consumer mode */
+               switch (chip->sample_rate) {
+               case 32000:
+                       control_reg |= GML_SPDIF_SAMPLE_RATE0 |
+                               GML_SPDIF_SAMPLE_RATE1;
+                       break;
+               case 48000:
+                       control_reg |= GML_SPDIF_SAMPLE_RATE1;
+                       break;
+               }
+       }
+
+       if ((err = write_control_reg(chip, control_reg, FALSE)))
+               return err;
+       chip->professional_spdif = prof;
+       DE_ACT(("set_professional_spdif to %s\n",
+               prof ? "Professional" : "Consumer"));
+       return 0;
+}
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c
new file mode 100644 (file)
index 0000000..29d6d12
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define ECHOGALS_FAMILY
+#define ECHOCARD_GINA20
+#define ECHOCARD_NAME "Gina20"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_INPUT_GAIN
+#define ECHOCARD_HAS_DIGITAL_IO
+#define ECHOCARD_HAS_EXTERNAL_CLOCK
+#define ECHOCARD_HAS_ADAT      FALSE
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 2 */
+#define PX_ANALOG_IN   10      /* 2 */
+#define PX_DIGITAL_IN  12      /* 2 */
+#define PX_NUM         14
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 8 */
+#define BX_DIGITAL_OUT 8       /* 2 */
+#define BX_ANALOG_IN   10      /* 2 */
+#define BX_DIGITAL_IN  12      /* 2 */
+#define BX_NUM         14
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_GINA20_DSP  0
+
+static const struct firmware card_fw[] = {
+       {0, "gina20_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0},      /* DSP 56301 Gina20 rev.0 */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+       .rate_min = 44100,
+       .rate_max = 48000,
+       .channels_min = 1,
+       .channels_max = 2,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+       /* One page (4k) contains 512 instructions. I don't know if the hw
+       supports lists longer than this. In this case periods_max=220 is a
+       safe limit to make sure the list never exceeds 512 instructions. */
+};
+
+
+#include "gina20_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c
new file mode 100644 (file)
index 0000000..2757c89
--- /dev/null
@@ -0,0 +1,215 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int set_professional_spdif(struct echoaudio *chip, char prof);
+static int update_flags(struct echoaudio *chip);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Gina20\n"));
+       snd_assert((subdevice_id & 0xfff0) == GINA20, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_GINA20_DSP];
+       chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
+       chip->clock_state = GD_CLOCK_UNDEF;
+       /* Since this card has no ASIC, mark it as loaded so everything
+          works OK */
+       chip->asic_loaded = TRUE;
+       chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
+               ECHO_CLOCK_BIT_SPDIF;
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+
+       err = set_professional_spdif(chip, TRUE);
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       u32 clocks_from_dsp, clock_bits;
+
+       /* Map the DSP clock detect bits to the generic driver clock
+          detect bits */
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       clock_bits = ECHO_CLOCK_BIT_INTERNAL;
+
+       if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
+               clock_bits |= ECHO_CLOCK_BIT_SPDIF;
+
+       return clock_bits;
+}
+
+
+
+/* The Gina20 has no ASIC. Just do nothing */
+static int load_asic(struct echoaudio *chip)
+{
+       return 0;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u8 clock_state, spdif_status;
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       switch (rate) {
+       case 44100:
+               clock_state = GD_CLOCK_44;
+               spdif_status = GD_SPDIF_STATUS_44;
+               break;
+       case 48000:
+               clock_state = GD_CLOCK_48;
+               spdif_status = GD_SPDIF_STATUS_48;
+               break;
+       default:
+               clock_state = GD_CLOCK_NOCHANGE;
+               spdif_status = GD_SPDIF_STATUS_NOCHANGE;
+               break;
+       }
+
+       if (chip->clock_state == clock_state)
+               clock_state = GD_CLOCK_NOCHANGE;
+       if (spdif_status == chip->spdif_status)
+               spdif_status = GD_SPDIF_STATUS_NOCHANGE;
+
+       chip->comm_page->sample_rate = cpu_to_le32(rate);
+       chip->comm_page->gd_clock_state = clock_state;
+       chip->comm_page->gd_spdif_status = spdif_status;
+       chip->comm_page->gd_resampler_state = 3;        /* magic number - should always be 3 */
+
+       /* Save the new audio state if it changed */
+       if (clock_state != GD_CLOCK_NOCHANGE)
+               chip->clock_state = clock_state;
+       if (spdif_status != GD_SPDIF_STATUS_NOCHANGE)
+               chip->spdif_status = spdif_status;
+       chip->sample_rate = rate;
+
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
+}
+
+
+
+static int set_input_clock(struct echoaudio *chip, u16 clock)
+{
+       DE_ACT(("set_input_clock:\n"));
+
+       switch (clock) {
+       case ECHO_CLOCK_INTERNAL:
+               /* Reset the audio state to unknown (just in case) */
+               chip->clock_state = GD_CLOCK_UNDEF;
+               chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
+               set_sample_rate(chip, chip->sample_rate);
+               chip->input_clock = clock;
+               DE_ACT(("Set Gina clock to INTERNAL\n"));
+               break;
+       case ECHO_CLOCK_SPDIF:
+               chip->comm_page->gd_clock_state = GD_CLOCK_SPDIFIN;
+               chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_NOCHANGE;
+               clear_handshake(chip);
+               send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
+               chip->clock_state = GD_CLOCK_SPDIFIN;
+               DE_ACT(("Set Gina20 clock to SPDIF\n"));
+               chip->input_clock = clock;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+
+/* Set input bus gain (one unit is 0.5dB !) */
+static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
+{
+       snd_assert(input < num_busses_in(chip), return -EINVAL);
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->input_gain[input] = gain;
+       gain += GL20_INPUT_GAIN_MAGIC_NUMBER;
+       chip->comm_page->line_in_level[input] = gain;
+       return 0;
+}
+
+
+
+/* Tell the DSP to reread the flags from the comm page */
+static int update_flags(struct echoaudio *chip)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_UPDATE_FLAGS);
+}
+
+
+
+static int set_professional_spdif(struct echoaudio *chip, char prof)
+{
+       DE_ACT(("set_professional_spdif %d\n", prof));
+       if (prof)
+               chip->comm_page->flags |=
+                       __constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+       else
+               chip->comm_page->flags &=
+                       ~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+       chip->professional_spdif = prof;
+       return update_flags(chip);
+}
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c
new file mode 100644 (file)
index 0000000..e464d72
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define ECHO24_FAMILY
+#define ECHOCARD_GINA24
+#define ECHOCARD_NAME "Gina24"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_ASIC
+#define ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_DIGITAL_IO
+#define ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
+#define ECHOCARD_HAS_DIGITAL_MODE_SWITCH
+#define ECHOCARD_HAS_EXTERNAL_CLOCK
+#define ECHOCARD_HAS_ADAT      6
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 8 */
+#define PX_ANALOG_IN   16      /* 2 */
+#define PX_DIGITAL_IN  18      /* 8 */
+#define PX_NUM         26
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 8 */
+#define BX_DIGITAL_OUT 8       /* 8 */
+#define BX_ANALOG_IN   16      /* 2 */
+#define BX_DIGITAL_IN  18      /* 8 */
+#define BX_NUM         26
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_361_LOADER          0
+#define FW_GINA24_301_DSP      1
+#define FW_GINA24_361_DSP      2
+#define FW_GINA24_301_ASIC     3
+#define FW_GINA24_361_ASIC     4
+
+static const struct firmware card_fw[] = {
+       {0, "loader_dsp.fw"},
+       {0, "gina24_301_dsp.fw"},
+       {0, "gina24_361_dsp.fw"},
+       {0, "gina24_301_asic.fw"},
+       {0, "gina24_361_asic.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0},      /* DSP 56301 Gina24 rev.0 */
+       {0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0},      /* DSP 56301 Gina24 rev.1 */
+       {0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0},      /* DSP 56361 Gina24 rev.0 */
+       {0x1057, 0x3410, 0xECC0, 0x0051, 0, 0, 0},      /* DSP 56361 Gina24 rev.1 */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_8000_48000 |
+                       SNDRV_PCM_RATE_88200 |
+                       SNDRV_PCM_RATE_96000,
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 1,
+       .channels_max = 8,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+       /* One page (4k) contains 512 instructions. I don't know if the hw
+       supports lists longer than this. In this case periods_max=220 is a
+       safe limit to make sure the list never exceeds 512 instructions.
+       220 ~= (512 - 1 - (BUFFER_BYTES_MAX / PAGE_SIZE)) / 2 */
+};
+
+#include "gina24_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio_gml.c"
+#include "echoaudio.c"
diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c
new file mode 100644 (file)
index 0000000..144fc56
--- /dev/null
@@ -0,0 +1,346 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int write_control_reg(struct echoaudio *chip, u32 value, char force);
+static int set_input_clock(struct echoaudio *chip, u16 clock);
+static int set_professional_spdif(struct echoaudio *chip, char prof);
+static int set_digital_mode(struct echoaudio *chip, u8 mode);
+static int load_asic_generic(struct echoaudio *chip, u32 cmd,
+                            const struct firmware *asic);
+static int check_asic_status(struct echoaudio *chip);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Gina24\n"));
+       snd_assert((subdevice_id & 0xfff0) == GINA24, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->input_clock_types =
+               ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
+               ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 |
+               ECHO_CLOCK_BIT_ADAT;
+       chip->professional_spdif = FALSE;
+       chip->digital_in_automute = TRUE;
+       chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
+
+       /* Gina24 comes in both '301 and '361 flavors */
+       if (chip->device_id == DEVICE_ID_56361) {
+               chip->dsp_code_to_load = &card_fw[FW_GINA24_361_DSP];
+               chip->digital_modes =
+                       ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
+                       ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
+                       ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
+       } else {
+               chip->dsp_code_to_load = &card_fw[FW_GINA24_301_DSP];
+               chip->digital_modes =
+                       ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
+                       ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
+                       ECHOCAPS_HAS_DIGITAL_MODE_ADAT |
+                       ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_CDROM;
+       }
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+       err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
+       snd_assert(err >= 0, return err);
+       err = set_professional_spdif(chip, TRUE);
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       u32 clocks_from_dsp, clock_bits;
+
+       /* Map the DSP clock detect bits to the generic driver clock
+          detect bits */
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       clock_bits = ECHO_CLOCK_BIT_INTERNAL;
+
+       if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF)
+               clock_bits |= ECHO_CLOCK_BIT_SPDIF;
+
+       if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_ADAT)
+               clock_bits |= ECHO_CLOCK_BIT_ADAT;
+
+       if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_ESYNC)
+               clock_bits |= ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96;
+
+       return clock_bits;
+}
+
+
+
+/* Gina24 has an ASIC on the PCI card which must be loaded for anything
+interesting to happen. */
+static int load_asic(struct echoaudio *chip)
+{
+       u32 control_reg;
+       int err;
+       const struct firmware *fw;
+
+       if (chip->asic_loaded)
+               return 1;
+
+       /* Give the DSP a few milliseconds to settle down */
+       mdelay(10);
+
+       /* Pick the correct ASIC for '301 or '361 Gina24 */
+       if (chip->device_id == DEVICE_ID_56361)
+               fw = &card_fw[FW_GINA24_361_ASIC];
+       else
+               fw = &card_fw[FW_GINA24_301_ASIC];
+
+       if ((err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, fw)) < 0)
+               return err;
+
+       chip->asic_code = fw;
+
+       /* Now give the new ASIC a little time to set up */
+       mdelay(10);
+       /* See if it worked */
+       err = check_asic_status(chip);
+
+       /* Set up the control register if the load succeeded -
+          48 kHz, internal clock, S/PDIF RCA mode */
+       if (!err) {
+               control_reg = GML_CONVERTER_ENABLE | GML_48KHZ;
+               err = write_control_reg(chip, control_reg, TRUE);
+       }
+       DE_INIT(("load_asic() done\n"));
+       return err;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u32 control_reg, clock;
+
+       snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
+                  return -EINVAL);
+
+       /* Only set the clock for internal mode. */
+       if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
+               DE_ACT(("set_sample_rate: Cannot set sample rate - "
+                       "clock not set to CLK_CLOCKININTERNAL\n"));
+               /* Save the rate anyhow */
+               chip->comm_page->sample_rate = cpu_to_le32(rate);
+               chip->sample_rate = rate;
+               return 0;
+       }
+
+       clock = 0;
+
+       control_reg = le32_to_cpu(chip->comm_page->control_register);
+       control_reg &= GML_CLOCK_CLEAR_MASK & GML_SPDIF_RATE_CLEAR_MASK;
+
+       switch (rate) {
+       case 96000:
+               clock = GML_96KHZ;
+               break;
+       case 88200:
+               clock = GML_88KHZ;
+               break;
+       case 48000:
+               clock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
+               break;
+       case 44100:
+               clock = GML_44KHZ;
+               /* Professional mode ? */
+               if (control_reg & GML_SPDIF_PRO_MODE)
+                       clock |= GML_SPDIF_SAMPLE_RATE0;
+               break;
+       case 32000:
+               clock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 |
+                       GML_SPDIF_SAMPLE_RATE1;
+               break;
+       case 22050:
+               clock = GML_22KHZ;
+               break;
+       case 16000:
+               clock = GML_16KHZ;
+               break;
+       case 11025:
+               clock = GML_11KHZ;
+               break;
+       case 8000:
+               clock = GML_8KHZ;
+               break;
+       default:
+               DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+               return -EINVAL;
+       }
+
+       control_reg |= clock;
+
+       chip->comm_page->sample_rate = cpu_to_le32(rate);       /* ignored by the DSP */
+       chip->sample_rate = rate;
+       DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+
+       return write_control_reg(chip, control_reg, FALSE);
+}
+
+
+
+static int set_input_clock(struct echoaudio *chip, u16 clock)
+{
+       u32 control_reg, clocks_from_dsp;
+
+       DE_ACT(("set_input_clock:\n"));
+
+       /* Mask off the clock select bits */
+       control_reg = le32_to_cpu(chip->comm_page->control_register) &
+               GML_CLOCK_CLEAR_MASK;
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       switch (clock) {
+       case ECHO_CLOCK_INTERNAL:
+               DE_ACT(("Set Gina24 clock to INTERNAL\n"));
+               chip->input_clock = ECHO_CLOCK_INTERNAL;
+               return set_sample_rate(chip, chip->sample_rate);
+       case ECHO_CLOCK_SPDIF:
+               if (chip->digital_mode == DIGITAL_MODE_ADAT)
+                       return -EAGAIN;
+               DE_ACT(("Set Gina24 clock to SPDIF\n"));
+               control_reg |= GML_SPDIF_CLOCK;
+               if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96)
+                       control_reg |= GML_DOUBLE_SPEED_MODE;
+               else
+                       control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               break;
+       case ECHO_CLOCK_ADAT:
+               if (chip->digital_mode != DIGITAL_MODE_ADAT)
+                       return -EAGAIN;
+               DE_ACT(("Set Gina24 clock to ADAT\n"));
+               control_reg |= GML_ADAT_CLOCK;
+               control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               break;
+       case ECHO_CLOCK_ESYNC:
+               DE_ACT(("Set Gina24 clock to ESYNC\n"));
+               control_reg |= GML_ESYNC_CLOCK;
+               control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               break;
+       case ECHO_CLOCK_ESYNC96:
+               DE_ACT(("Set Gina24 clock to ESYNC96\n"));
+               control_reg |= GML_ESYNC_CLOCK | GML_DOUBLE_SPEED_MODE;
+               break;
+       default:
+               DE_ACT(("Input clock 0x%x not supported for Gina24\n", clock));
+               return -EINVAL;
+       }
+
+       chip->input_clock = clock;
+       return write_control_reg(chip, control_reg, TRUE);
+}
+
+
+
+static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
+{
+       u32 control_reg;
+       int err, incompatible_clock;
+
+       /* Set clock to "internal" if it's not compatible with the new mode */
+       incompatible_clock = FALSE;
+       switch (mode) {
+       case DIGITAL_MODE_SPDIF_OPTICAL:
+       case DIGITAL_MODE_SPDIF_CDROM:
+       case DIGITAL_MODE_SPDIF_RCA:
+               if (chip->input_clock == ECHO_CLOCK_ADAT)
+                       incompatible_clock = TRUE;
+               break;
+       case DIGITAL_MODE_ADAT:
+               if (chip->input_clock == ECHO_CLOCK_SPDIF)
+                       incompatible_clock = TRUE;
+               break;
+       default:
+               DE_ACT(("Digital mode not supported: %d\n", mode));
+               return -EINVAL;
+       }
+
+       spin_lock_irq(&chip->lock);
+
+       if (incompatible_clock) {       /* Switch to 48KHz, internal */
+               chip->sample_rate = 48000;
+               set_input_clock(chip, ECHO_CLOCK_INTERNAL);
+       }
+
+       /* Clear the current digital mode */
+       control_reg = le32_to_cpu(chip->comm_page->control_register);
+       control_reg &= GML_DIGITAL_MODE_CLEAR_MASK;
+
+       /* Tweak the control reg */
+       switch (mode) {
+       case DIGITAL_MODE_SPDIF_OPTICAL:
+               control_reg |= GML_SPDIF_OPTICAL_MODE;
+               break;
+       case DIGITAL_MODE_SPDIF_CDROM:
+               /* '361 Gina24 cards do not have the S/PDIF CD-ROM mode */
+               if (chip->device_id == DEVICE_ID_56301)
+                       control_reg |= GML_SPDIF_CDROM_MODE;
+               break;
+       case DIGITAL_MODE_SPDIF_RCA:
+               /* GML_SPDIF_OPTICAL_MODE bit cleared */
+               break;
+       case DIGITAL_MODE_ADAT:
+               control_reg |= GML_ADAT_MODE;
+               control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               break;
+       }
+
+       err = write_control_reg(chip, control_reg, TRUE);
+       spin_unlock_irq(&chip->lock);
+       if (err < 0)
+               return err;
+       chip->digital_mode = mode;
+
+       DE_ACT(("set_digital_mode to %d\n", chip->digital_mode));
+       return incompatible_clock;
+}
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c
new file mode 100644 (file)
index 0000000..bfd2467
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define INDIGO_FAMILY
+#define ECHOCARD_INDIGO
+#define ECHOCARD_NAME "Indigo"
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_VMIXER
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 0 */
+#define PX_ANALOG_IN   8       /* 0 */
+#define PX_DIGITAL_IN  8       /* 0 */
+#define PX_NUM         8
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 2 */
+#define BX_DIGITAL_OUT 2       /* 0 */
+#define BX_ANALOG_IN   2       /* 0 */
+#define BX_DIGITAL_IN  2       /* 0 */
+#define BX_NUM         2
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_361_LOADER  0
+#define FW_INDIGO_DSP  1
+
+static const struct firmware card_fw[] = {
+       {0, "loader_dsp.fw"},
+       {0, "indigo_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0},      /* Indigo */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_32000 |
+                       SNDRV_PCM_RATE_44100 |
+                       SNDRV_PCM_RATE_48000 |
+                       SNDRV_PCM_RATE_88200 |
+                       SNDRV_PCM_RATE_96000,
+       .rate_min = 32000,
+       .rate_max = 96000,
+       .channels_min = 1,
+       .channels_max = 8,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+};
+
+#include "indigo_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
+
diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c
new file mode 100644 (file)
index 0000000..d6ac773
--- /dev/null
@@ -0,0 +1,170 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
+                          int gain);
+static int update_vmixer_level(struct echoaudio *chip);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Indigo\n"));
+       snd_assert((subdevice_id & 0xfff0) == INDIGO, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_INDIGO_DSP];
+       /* Since this card has no ASIC, mark it as loaded so everything
+          works OK */
+       chip->asic_loaded = TRUE;
+       chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+
+       /* Default routing of the virtual channels: all vchannels are routed
+       to the stereo output */
+       set_vmixer_gain(chip, 0, 0, 0);
+       set_vmixer_gain(chip, 1, 1, 0);
+       set_vmixer_gain(chip, 0, 2, 0);
+       set_vmixer_gain(chip, 1, 3, 0);
+       set_vmixer_gain(chip, 0, 4, 0);
+       set_vmixer_gain(chip, 1, 5, 0);
+       set_vmixer_gain(chip, 0, 6, 0);
+       set_vmixer_gain(chip, 1, 7, 0);
+       err = update_vmixer_level(chip);
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       return ECHO_CLOCK_BIT_INTERNAL;
+}
+
+
+
+/* The Indigo has no ASIC. Just do nothing */
+static int load_asic(struct echoaudio *chip)
+{
+       return 0;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u32 control_reg;
+
+       switch (rate) {
+       case 96000:
+               control_reg = MIA_96000;
+               break;
+       case 88200:
+               control_reg = MIA_88200;
+               break;
+       case 48000:
+               control_reg = MIA_48000;
+               break;
+       case 44100:
+               control_reg = MIA_44100;
+               break;
+       case 32000:
+               control_reg = MIA_32000;
+               break;
+       default:
+               DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+               return -EINVAL;
+       }
+
+       /* Set the control register if it has changed */
+       if (control_reg != le32_to_cpu(chip->comm_page->control_register)) {
+               if (wait_handshake(chip))
+                       return -EIO;
+
+               chip->comm_page->sample_rate = cpu_to_le32(rate);       /* ignored by the DSP */
+               chip->comm_page->control_register = cpu_to_le32(control_reg);
+               chip->sample_rate = rate;
+
+               clear_handshake(chip);
+               return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
+       }
+       return 0;
+}
+
+
+
+/* This function routes the sound from a virtual channel to a real output */
+static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
+                          int gain)
+{
+       int index;
+
+       snd_assert(pipe < num_pipes_out(chip) &&
+                  output < num_busses_out(chip), return -EINVAL);
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->vmixer_gain[output][pipe] = gain;
+       index = output * num_pipes_out(chip) + pipe;
+       chip->comm_page->vmixer[index] = gain;
+
+       DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+       return 0;
+}
+
+
+
+/* Tell the DSP to read and update virtual mixer levels in comm page. */
+static int update_vmixer_level(struct echoaudio *chip)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
+}
+
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c
new file mode 100644 (file)
index 0000000..8ed7ff1
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define INDIGO_FAMILY
+#define ECHOCARD_INDIGO_DJ
+#define ECHOCARD_NAME "Indigo DJ"
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_VMIXER
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 0 */
+#define PX_ANALOG_IN   8       /* 0 */
+#define PX_DIGITAL_IN  8       /* 0 */
+#define PX_NUM         8
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 4 */
+#define BX_DIGITAL_OUT 4       /* 0 */
+#define BX_ANALOG_IN   4       /* 0 */
+#define BX_DIGITAL_IN  4       /* 0 */
+#define BX_NUM         4
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_361_LOADER          0
+#define FW_INDIGO_DJ_DSP       1
+
+static const struct firmware card_fw[] = {
+       {0, "loader_dsp.fw"},
+       {0, "indigo_dj_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0},      /* Indigo DJ*/
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_32000 |
+                       SNDRV_PCM_RATE_44100 |
+                       SNDRV_PCM_RATE_48000 |
+                       SNDRV_PCM_RATE_88200 |
+                       SNDRV_PCM_RATE_96000,
+       .rate_min = 32000,
+       .rate_max = 96000,
+       .channels_min = 1,
+       .channels_max = 4,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+};
+
+#include "indigodj_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
+
diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c
new file mode 100644 (file)
index 0000000..500e150
--- /dev/null
@@ -0,0 +1,170 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
+                          int gain);
+static int update_vmixer_level(struct echoaudio *chip);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Indigo DJ\n"));
+       snd_assert((subdevice_id & 0xfff0) == INDIGO_DJ, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJ_DSP];
+       /* Since this card has no ASIC, mark it as loaded so everything
+          works OK */
+       chip->asic_loaded = TRUE;
+       chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+
+       /* Default routing of the virtual channels: vchannels 0-3 and
+       vchannels 4-7 are routed to real channels 0-4 */
+       set_vmixer_gain(chip, 0, 0, 0);
+       set_vmixer_gain(chip, 1, 1, 0);
+       set_vmixer_gain(chip, 2, 2, 0);
+       set_vmixer_gain(chip, 3, 3, 0);
+       set_vmixer_gain(chip, 0, 4, 0);
+       set_vmixer_gain(chip, 1, 5, 0);
+       set_vmixer_gain(chip, 2, 6, 0);
+       set_vmixer_gain(chip, 3, 7, 0);
+       err = update_vmixer_level(chip);
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       return ECHO_CLOCK_BIT_INTERNAL;
+}
+
+
+
+/* The IndigoDJ has no ASIC. Just do nothing */
+static int load_asic(struct echoaudio *chip)
+{
+       return 0;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u32 control_reg;
+
+       switch (rate) {
+       case 96000:
+               control_reg = MIA_96000;
+               break;
+       case 88200:
+               control_reg = MIA_88200;
+               break;
+       case 48000:
+               control_reg = MIA_48000;
+               break;
+       case 44100:
+               control_reg = MIA_44100;
+               break;
+       case 32000:
+               control_reg = MIA_32000;
+               break;
+       default:
+               DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+               return -EINVAL;
+       }
+
+       /* Set the control register if it has changed */
+       if (control_reg != le32_to_cpu(chip->comm_page->control_register)) {
+               if (wait_handshake(chip))
+                       return -EIO;
+
+               chip->comm_page->sample_rate = cpu_to_le32(rate);       /* ignored by the DSP */
+               chip->comm_page->control_register = cpu_to_le32(control_reg);
+               chip->sample_rate = rate;
+
+               clear_handshake(chip);
+               return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
+       }
+       return 0;
+}
+
+
+
+/* This function routes the sound from a virtual channel to a real output */
+static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
+                          int gain)
+{
+       int index;
+
+       snd_assert(pipe < num_pipes_out(chip) &&
+                  output < num_busses_out(chip), return -EINVAL);
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->vmixer_gain[output][pipe] = gain;
+       index = output * num_pipes_out(chip) + pipe;
+       chip->comm_page->vmixer[index] = gain;
+
+       DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+       return 0;
+}
+
+
+
+/* Tell the DSP to read and update virtual mixer levels in comm page. */
+static int update_vmixer_level(struct echoaudio *chip)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
+}
+
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c
new file mode 100644 (file)
index 0000000..a8788e9
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define INDIGO_FAMILY
+#define ECHOCARD_INDIGO_IO
+#define ECHOCARD_NAME "Indigo IO"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_VMIXER
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 0 */
+#define PX_ANALOG_IN   8       /* 2 */
+#define PX_DIGITAL_IN  10      /* 0 */
+#define PX_NUM         10
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 2 */
+#define BX_DIGITAL_OUT 2       /* 0 */
+#define BX_ANALOG_IN   2       /* 2 */
+#define BX_DIGITAL_IN  4       /* 0 */
+#define BX_NUM         4
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_361_LOADER          0
+#define FW_INDIGO_IO_DSP       1
+
+static const struct firmware card_fw[] = {
+       {0, "loader_dsp.fw"},
+       {0, "indigo_io_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0},      /* Indigo IO*/
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_32000 |
+                       SNDRV_PCM_RATE_44100 |
+                       SNDRV_PCM_RATE_48000 |
+                       SNDRV_PCM_RATE_88200 |
+                       SNDRV_PCM_RATE_96000,
+       .rate_min = 32000,
+       .rate_max = 96000,
+       .channels_min = 1,
+       .channels_max = 8,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+};
+
+#include "indigoio_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
+
diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c
new file mode 100644 (file)
index 0000000..f3ad13d
--- /dev/null
@@ -0,0 +1,141 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
+                          int gain);
+static int update_vmixer_level(struct echoaudio *chip);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Indigo IO\n"));
+       snd_assert((subdevice_id & 0xfff0) == INDIGO_IO, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_INDIGO_IO_DSP];
+       /* Since this card has no ASIC, mark it as loaded so everything
+          works OK */
+       chip->asic_loaded = TRUE;
+       chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+
+       /* Default routing of the virtual channels: all vchannels are routed
+       to the stereo output */
+       set_vmixer_gain(chip, 0, 0, 0);
+       set_vmixer_gain(chip, 1, 1, 0);
+       set_vmixer_gain(chip, 0, 2, 0);
+       set_vmixer_gain(chip, 1, 3, 0);
+       set_vmixer_gain(chip, 0, 4, 0);
+       set_vmixer_gain(chip, 1, 5, 0);
+       set_vmixer_gain(chip, 0, 6, 0);
+       set_vmixer_gain(chip, 1, 7, 0);
+       err = update_vmixer_level(chip);
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       return ECHO_CLOCK_BIT_INTERNAL;
+}
+
+
+
+/* The IndigoIO has no ASIC. Just do nothing */
+static int load_asic(struct echoaudio *chip)
+{
+       return 0;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->sample_rate = rate;
+       chip->comm_page->sample_rate = cpu_to_le32(rate);
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
+}
+
+
+
+/* This function routes the sound from a virtual channel to a real output */
+static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
+                          int gain)
+{
+       int index;
+
+       snd_assert(pipe < num_pipes_out(chip) &&
+                  output < num_busses_out(chip), return -EINVAL);
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->vmixer_gain[output][pipe] = gain;
+       index = output * num_pipes_out(chip) + pipe;
+       chip->comm_page->vmixer[index] = gain;
+
+       DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+       return 0;
+}
+
+
+
+/* Tell the DSP to read and update virtual mixer levels in comm page. */
+static int update_vmixer_level(struct echoaudio *chip)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
+}
+
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c
new file mode 100644 (file)
index 0000000..e503d74
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define ECHOGALS_FAMILY
+#define ECHOCARD_LAYLA20
+#define ECHOCARD_NAME "Layla20"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_ASIC
+#define ECHOCARD_HAS_INPUT_GAIN
+#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_DIGITAL_IO
+#define ECHOCARD_HAS_EXTERNAL_CLOCK
+#define ECHOCARD_HAS_ADAT      FALSE
+#define ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH
+#define ECHOCARD_HAS_MIDI
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 10 */
+#define PX_DIGITAL_OUT 10      /*  2 */
+#define PX_ANALOG_IN   12      /*  8 */
+#define PX_DIGITAL_IN  20      /*  2 */
+#define PX_NUM         22
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 10 */
+#define BX_DIGITAL_OUT 10      /*  2 */
+#define BX_ANALOG_IN   12      /*  8 */
+#define BX_DIGITAL_IN  20      /*  2 */
+#define BX_NUM         22
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_LAYLA20_DSP 0
+#define FW_LAYLA20_ASIC        1
+
+static const struct firmware card_fw[] = {
+       {0, "layla20_dsp.fw"},
+       {0, "layla20_asic.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0},      /* DSP 56301 Layla20 rev.0 */
+       {0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0},      /* DSP 56301 Layla20 rev.1 */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS,
+       .rate_min = 8000,
+       .rate_max = 50000,
+       .channels_min = 1,
+       .channels_max = 10,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+       /* One page (4k) contains 512 instructions. I don't know if the hw
+       supports lists longer than this. In this case periods_max=220 is a
+       safe limit to make sure the list never exceeds 512 instructions. */
+};
+
+#include "layla20_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
+#include "midi.c"
diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c
new file mode 100644 (file)
index 0000000..990c9a6
--- /dev/null
@@ -0,0 +1,290 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int read_dsp(struct echoaudio *chip, u32 *data);
+static int set_professional_spdif(struct echoaudio *chip, char prof);
+static int load_asic_generic(struct echoaudio *chip, u32 cmd,
+                            const struct firmware *asic);
+static int check_asic_status(struct echoaudio *chip);
+static int update_flags(struct echoaudio *chip);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Layla20\n"));
+       snd_assert((subdevice_id & 0xfff0) == LAYLA20, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->has_midi = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_LAYLA20_DSP];
+       chip->input_clock_types =
+               ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
+               ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;
+       chip->output_clock_types =
+               ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+
+       err = set_professional_spdif(chip, TRUE);
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       u32 clocks_from_dsp, clock_bits;
+
+       /* Map the DSP clock detect bits to the generic driver clock detect bits */
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       clock_bits = ECHO_CLOCK_BIT_INTERNAL;
+
+       if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
+               clock_bits |= ECHO_CLOCK_BIT_SPDIF;
+
+       if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_WORD) {
+               if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SUPER)
+                       clock_bits |= ECHO_CLOCK_BIT_SUPER;
+               else
+                       clock_bits |= ECHO_CLOCK_BIT_WORD;
+       }
+
+       return clock_bits;
+}
+
+
+
+/* ASIC status check - some cards have one or two ASICs that need to be
+loaded.  Once that load is complete, this function is called to see if
+the load was successful.
+If this load fails, it does not necessarily mean that the hardware is
+defective - the external box may be disconnected or turned off.
+This routine sometimes fails for Layla20; for Layla20, the loop runs
+5 times and succeeds if it wins on three of the loops. */
+static int check_asic_status(struct echoaudio *chip)
+{
+       u32 asic_status;
+       int goodcnt, i;
+
+       chip->asic_loaded = FALSE;
+       for (i = goodcnt = 0; i < 5; i++) {
+               send_vector(chip, DSP_VC_TEST_ASIC);
+
+               /* The DSP will return a value to indicate whether or not
+                  the ASIC is currently loaded */
+               if (read_dsp(chip, &asic_status) < 0) {
+                       DE_ACT(("check_asic_status: failed on read_dsp\n"));
+                       return -EIO;
+               }
+
+               if (asic_status == ASIC_ALREADY_LOADED) {
+                       if (++goodcnt == 3) {
+                               chip->asic_loaded = TRUE;
+                               return 0;
+                       }
+               }
+       }
+       return -EIO;
+}
+
+
+
+/* Layla20 has an ASIC in the external box */
+static int load_asic(struct echoaudio *chip)
+{
+       int err;
+
+       if (chip->asic_loaded)
+               return 0;
+
+       err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC,
+                               &card_fw[FW_LAYLA20_ASIC]);
+       if (err < 0)
+               return err;
+
+       /* Check if ASIC is alive and well. */
+       return check_asic_status(chip);
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       snd_assert(rate >= 8000 && rate <= 50000, return -EINVAL);
+
+       /* Only set the clock for internal mode. Do not return failure,
+          simply treat it as a non-event. */
+       if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
+               DE_ACT(("set_sample_rate: Cannot set sample rate - "
+                       "clock not set to CLK_CLOCKININTERNAL\n"));
+               chip->comm_page->sample_rate = cpu_to_le32(rate);
+               chip->sample_rate = rate;
+               return 0;
+       }
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       DE_ACT(("set_sample_rate(%d)\n", rate));
+       chip->sample_rate = rate;
+       chip->comm_page->sample_rate = cpu_to_le32(rate);
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_SET_LAYLA_SAMPLE_RATE);
+}
+
+
+
+static int set_input_clock(struct echoaudio *chip, u16 clock_source)
+{
+       u16 clock;
+       u32 rate;
+
+       DE_ACT(("set_input_clock:\n"));
+       rate = 0;
+       switch (clock_source) {
+       case ECHO_CLOCK_INTERNAL:
+               DE_ACT(("Set Layla20 clock to INTERNAL\n"));
+               rate = chip->sample_rate;
+               clock = LAYLA20_CLOCK_INTERNAL;
+               break;
+       case ECHO_CLOCK_SPDIF:
+               DE_ACT(("Set Layla20 clock to SPDIF\n"));
+               clock = LAYLA20_CLOCK_SPDIF;
+               break;
+       case ECHO_CLOCK_WORD:
+               DE_ACT(("Set Layla20 clock to WORD\n"));
+               clock = LAYLA20_CLOCK_WORD;
+               break;
+       case ECHO_CLOCK_SUPER:
+               DE_ACT(("Set Layla20 clock to SUPER\n"));
+               clock = LAYLA20_CLOCK_SUPER;
+               break;
+       default:
+               DE_ACT(("Input clock 0x%x not supported for Layla24\n",
+                       clock_source));
+               return -EINVAL;
+       }
+       chip->input_clock = clock_source;
+
+       chip->comm_page->input_clock = cpu_to_le16(clock);
+       clear_handshake(chip);
+       send_vector(chip, DSP_VC_UPDATE_CLOCKS);
+
+       if (rate)
+               set_sample_rate(chip, rate);
+
+       return 0;
+}
+
+
+
+static int set_output_clock(struct echoaudio *chip, u16 clock)
+{
+       DE_ACT(("set_output_clock: %d\n", clock));
+       switch (clock) {
+       case ECHO_CLOCK_SUPER:
+               clock = LAYLA20_OUTPUT_CLOCK_SUPER;
+               break;
+       case ECHO_CLOCK_WORD:
+               clock = LAYLA20_OUTPUT_CLOCK_WORD;
+               break;
+       default:
+               DE_ACT(("set_output_clock wrong clock\n"));
+               return -EINVAL;
+       }
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->comm_page->output_clock = cpu_to_le16(clock);
+       chip->output_clock = clock;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
+}
+
+
+
+/* Set input bus gain (one unit is 0.5dB !) */
+static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
+{
+       snd_assert(input < num_busses_in(chip), return -EINVAL);
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->input_gain[input] = gain;
+       gain += GL20_INPUT_GAIN_MAGIC_NUMBER;
+       chip->comm_page->line_in_level[input] = gain;
+       return 0;
+}
+
+
+
+/* Tell the DSP to reread the flags from the comm page */
+static int update_flags(struct echoaudio *chip)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_UPDATE_FLAGS);
+}
+
+
+
+static int set_professional_spdif(struct echoaudio *chip, char prof)
+{
+       DE_ACT(("set_professional_spdif %d\n", prof));
+       if (prof)
+               chip->comm_page->flags |=
+                       __constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+       else
+               chip->comm_page->flags &=
+                       ~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+       chip->professional_spdif = prof;
+       return update_flags(chip);
+}
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c
new file mode 100644 (file)
index 0000000..d4581fd
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define ECHO24_FAMILY
+#define ECHOCARD_LAYLA24
+#define ECHOCARD_NAME "Layla24"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_ASIC
+#define ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_DIGITAL_IO
+#define ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
+#define ECHOCARD_HAS_DIGITAL_MODE_SWITCH
+#define ECHOCARD_HAS_EXTERNAL_CLOCK
+#define ECHOCARD_HAS_ADAT      6
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+#define ECHOCARD_HAS_MIDI
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 8 */
+#define PX_ANALOG_IN   16      /* 8 */
+#define PX_DIGITAL_IN  24      /* 8 */
+#define PX_NUM         32
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 8 */
+#define BX_DIGITAL_OUT 8       /* 8 */
+#define BX_ANALOG_IN   16      /* 8 */
+#define BX_DIGITAL_IN  24      /* 8 */
+#define BX_NUM         32
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_361_LOADER          0
+#define FW_LAYLA24_DSP         1
+#define FW_LAYLA24_1_ASIC      2
+#define FW_LAYLA24_2A_ASIC     3
+#define FW_LAYLA24_2S_ASIC     4
+
+static const struct firmware card_fw[] = {
+       {0, "loader_dsp.fw"},
+       {0, "layla24_dsp.fw"},
+       {0, "layla24_1_asic.fw"},
+       {0, "layla24_2A_asic.fw"},
+       {0, "layla24_2S_asic.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0},      /* DSP 56361 Layla24 rev.0 */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_8000_96000,
+       .rate_min = 8000,
+       .rate_max = 100000,
+       .channels_min = 1,
+       .channels_max = 8,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+       /* One page (4k) contains 512 instructions. I don't know if the hw
+       supports lists longer than this. In this case periods_max=220 is a
+       safe limit to make sure the list never exceeds 512 instructions. */
+};
+
+
+#include "layla24_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio_gml.c"
+#include "echoaudio.c"
+#include "midi.c"
diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c
new file mode 100644 (file)
index 0000000..7ec5b63
--- /dev/null
@@ -0,0 +1,394 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int write_control_reg(struct echoaudio *chip, u32 value, char force);
+static int set_input_clock(struct echoaudio *chip, u16 clock);
+static int set_professional_spdif(struct echoaudio *chip, char prof);
+static int set_digital_mode(struct echoaudio *chip, u8 mode);
+static int load_asic_generic(struct echoaudio *chip, u32 cmd,
+                            const struct firmware *asic);
+static int check_asic_status(struct echoaudio *chip);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Layla24\n"));
+       snd_assert((subdevice_id & 0xfff0) == LAYLA24, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->has_midi = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_LAYLA24_DSP];
+       chip->input_clock_types =
+               ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
+               ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT;
+       chip->digital_modes =
+               ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
+               ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
+               ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
+       chip->digital_mode =            DIGITAL_MODE_SPDIF_RCA;
+       chip->professional_spdif = FALSE;
+       chip->digital_in_automute = TRUE;
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+
+       err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
+       snd_assert(err >= 0, return err);
+       err = set_professional_spdif(chip, TRUE);
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       u32 clocks_from_dsp, clock_bits;
+
+       /* Map the DSP clock detect bits to the generic driver clock detect bits */
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       clock_bits = ECHO_CLOCK_BIT_INTERNAL;
+
+       if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF)
+               clock_bits |= ECHO_CLOCK_BIT_SPDIF;
+
+       if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_ADAT)
+               clock_bits |= ECHO_CLOCK_BIT_ADAT;
+
+       if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_WORD)
+               clock_bits |= ECHO_CLOCK_BIT_WORD;
+
+       return clock_bits;
+}
+
+
+
+/* Layla24 has an ASIC on the PCI card and another ASIC in the external box;
+both need to be loaded. */
+static int load_asic(struct echoaudio *chip)
+{
+       int err;
+
+       if (chip->asic_loaded)
+               return 1;
+
+       DE_INIT(("load_asic\n"));
+
+       /* Give the DSP a few milliseconds to settle down */
+       mdelay(10);
+
+       /* Load the ASIC for the PCI card */
+       err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC,
+                               &card_fw[FW_LAYLA24_1_ASIC]);
+       if (err < 0)
+               return err;
+
+       chip->asic_code = &card_fw[FW_LAYLA24_2S_ASIC];
+
+       /* Now give the new ASIC a little time to set up */
+       mdelay(10);
+
+       /* Do the external one */
+       err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC,
+                               &card_fw[FW_LAYLA24_2S_ASIC]);
+       if (err < 0)
+               return FALSE;
+
+       /* Now give the external ASIC a little time to set up */
+       mdelay(10);
+
+       /* See if it worked */
+       err = check_asic_status(chip);
+
+       /* Set up the control register if the load succeeded -
+          48 kHz, internal clock, S/PDIF RCA mode */
+       if (!err)
+               err = write_control_reg(chip, GML_CONVERTER_ENABLE | GML_48KHZ,
+                                       TRUE);
+       
+       DE_INIT(("load_asic() done\n"));
+       return err;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u32 control_reg, clock, base_rate;
+
+       snd_assert(rate < 50000 || chip->digital_mode != DIGITAL_MODE_ADAT,
+                  return -EINVAL);
+
+       /* Only set the clock for internal mode. */
+       if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
+               DE_ACT(("set_sample_rate: Cannot set sample rate - "
+                       "clock not set to CLK_CLOCKININTERNAL\n"));
+               /* Save the rate anyhow */
+               chip->comm_page->sample_rate = cpu_to_le32(rate);
+               chip->sample_rate = rate;
+               return 0;
+       }
+
+       /* Get the control register & clear the appropriate bits */
+       control_reg = le32_to_cpu(chip->comm_page->control_register);
+       control_reg &= GML_CLOCK_CLEAR_MASK & GML_SPDIF_RATE_CLEAR_MASK;
+
+       clock = 0;
+
+       switch (rate) {
+       case 96000:
+               clock = GML_96KHZ;
+               break;
+       case 88200:
+               clock = GML_88KHZ;
+               break;
+       case 48000:
+               clock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
+               break;
+       case 44100:
+               clock = GML_44KHZ;
+               /* Professional mode */
+               if (control_reg & GML_SPDIF_PRO_MODE)
+                       clock |= GML_SPDIF_SAMPLE_RATE0;
+               break;
+       case 32000:
+               clock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 |
+                       GML_SPDIF_SAMPLE_RATE1;
+               break;
+       case 22050:
+               clock = GML_22KHZ;
+               break;
+       case 16000:
+               clock = GML_16KHZ;
+               break;
+       case 11025:
+               clock = GML_11KHZ;
+               break;
+       case 8000:
+               clock = GML_8KHZ;
+               break;
+       default:
+               /* If this is a non-standard rate, then the driver needs to
+               use Layla24's special "continuous frequency" mode */
+               clock = LAYLA24_CONTINUOUS_CLOCK;
+               if (rate > 50000) {
+                       base_rate = rate >> 1;
+                       control_reg |= GML_DOUBLE_SPEED_MODE;
+               } else {
+                       base_rate = rate;
+               }
+
+               if (base_rate < 25000)
+                       base_rate = 25000;
+
+               if (wait_handshake(chip))
+                       return -EIO;
+
+               chip->comm_page->sample_rate =
+                       cpu_to_le32(LAYLA24_MAGIC_NUMBER / base_rate - 2);
+
+               clear_handshake(chip);
+               send_vector(chip, DSP_VC_SET_LAYLA24_FREQUENCY_REG);
+       }
+
+       control_reg |= clock;
+
+       chip->comm_page->sample_rate = cpu_to_le32(rate);       /* ignored by the DSP ? */
+       chip->sample_rate = rate;
+       DE_ACT(("set_sample_rate: %d clock %d\n", rate, control_reg));
+
+       return write_control_reg(chip, control_reg, FALSE);
+}
+
+
+
+static int set_input_clock(struct echoaudio *chip, u16 clock)
+{
+       u32 control_reg, clocks_from_dsp;
+
+       /* Mask off the clock select bits */
+       control_reg = le32_to_cpu(chip->comm_page->control_register) &
+               GML_CLOCK_CLEAR_MASK;
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       /* Pick the new clock */
+       switch (clock) {
+       case ECHO_CLOCK_INTERNAL:
+               DE_ACT(("Set Layla24 clock to INTERNAL\n"));
+               chip->input_clock = ECHO_CLOCK_INTERNAL;
+               return set_sample_rate(chip, chip->sample_rate);
+       case ECHO_CLOCK_SPDIF:
+               if (chip->digital_mode == DIGITAL_MODE_ADAT)
+                       return -EAGAIN;
+               control_reg |= GML_SPDIF_CLOCK;
+               /* Layla24 doesn't support 96KHz S/PDIF */
+               control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               DE_ACT(("Set Layla24 clock to SPDIF\n"));
+               break;
+       case ECHO_CLOCK_WORD:
+               control_reg |= GML_WORD_CLOCK;
+               if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_WORD96)
+                       control_reg |= GML_DOUBLE_SPEED_MODE;
+               else
+                       control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               DE_ACT(("Set Layla24 clock to WORD\n"));
+               break;
+       case ECHO_CLOCK_ADAT:
+               if (chip->digital_mode != DIGITAL_MODE_ADAT)
+                       return -EAGAIN;
+               control_reg |= GML_ADAT_CLOCK;
+               control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               DE_ACT(("Set Layla24 clock to ADAT\n"));
+               break;
+       default:
+               DE_ACT(("Input clock 0x%x not supported for Layla24\n", clock));
+               return -EINVAL;
+       }
+
+       chip->input_clock = clock;
+       return write_control_reg(chip, control_reg, TRUE);
+}
+
+
+
+/* Depending on what digital mode you want, Layla24 needs different ASICs
+loaded.  This function checks the ASIC needed for the new mode and sees
+if it matches the one already loaded. */
+static int switch_asic(struct echoaudio *chip, const struct firmware *asic)
+{
+       s8 *monitors;
+
+       /*  Check to see if this is already loaded */
+       if (asic != chip->asic_code) {
+               monitors = kmalloc(MONITOR_ARRAY_SIZE, GFP_KERNEL);
+               if (! monitors)
+                       return -ENOMEM;
+
+               memcpy(monitors, chip->comm_page->monitors, MONITOR_ARRAY_SIZE);
+               memset(chip->comm_page->monitors, ECHOGAIN_MUTED,
+                      MONITOR_ARRAY_SIZE);
+
+               /* Load the desired ASIC */
+               if (load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC,
+                                     asic) < 0) {
+                       memcpy(chip->comm_page->monitors, monitors,
+                              MONITOR_ARRAY_SIZE);
+                       kfree(monitors);
+                       return -EIO;
+               }
+               chip->asic_code = asic;
+               memcpy(chip->comm_page->monitors, monitors, MONITOR_ARRAY_SIZE);
+               kfree(monitors);
+       }
+
+       return 0;
+}
+
+
+
+static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
+{
+       u32 control_reg;
+       int err, incompatible_clock;
+       const struct firmware *asic;
+
+       /* Set clock to "internal" if it's not compatible with the new mode */
+       incompatible_clock = FALSE;
+       switch (mode) {
+       case DIGITAL_MODE_SPDIF_OPTICAL:
+       case DIGITAL_MODE_SPDIF_RCA:
+               if (chip->input_clock == ECHO_CLOCK_ADAT)
+                       incompatible_clock = TRUE;
+               asic = &card_fw[FW_LAYLA24_2S_ASIC];
+               break;
+       case DIGITAL_MODE_ADAT:
+               if (chip->input_clock == ECHO_CLOCK_SPDIF)
+                       incompatible_clock = TRUE;
+               asic = &card_fw[FW_LAYLA24_2A_ASIC];
+               break;
+       default:
+               DE_ACT(("Digital mode not supported: %d\n", mode));
+               return -EINVAL;
+       }
+
+       if (incompatible_clock) {       /* Switch to 48KHz, internal */
+               chip->sample_rate = 48000;
+               spin_lock_irq(&chip->lock);
+               set_input_clock(chip, ECHO_CLOCK_INTERNAL);
+               spin_unlock_irq(&chip->lock);
+       }
+
+       /* switch_asic() can sleep */
+       if (switch_asic(chip, asic) < 0)
+               return -EIO;
+
+       spin_lock_irq(&chip->lock);
+
+       /* Tweak the control register */
+       control_reg = le32_to_cpu(chip->comm_page->control_register);
+       control_reg &= GML_DIGITAL_MODE_CLEAR_MASK;
+
+       switch (mode) {
+       case DIGITAL_MODE_SPDIF_OPTICAL:
+               control_reg |= GML_SPDIF_OPTICAL_MODE;
+               break;
+       case DIGITAL_MODE_SPDIF_RCA:
+               /* GML_SPDIF_OPTICAL_MODE bit cleared */
+               break;
+       case DIGITAL_MODE_ADAT:
+               control_reg |= GML_ADAT_MODE;
+               control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               break;
+       }
+
+       err = write_control_reg(chip, control_reg, TRUE);
+       spin_unlock_irq(&chip->lock);
+       if (err < 0)
+               return err;
+       chip->digital_mode = mode;
+
+       DE_ACT(("set_digital_mode to %d\n", mode));
+       return incompatible_clock;
+}
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c
new file mode 100644 (file)
index 0000000..be40c64
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define ECHO24_FAMILY
+#define ECHOCARD_MIA
+#define ECHOCARD_NAME "Mia"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_VMIXER
+#define ECHOCARD_HAS_DIGITAL_IO
+#define ECHOCARD_HAS_EXTERNAL_CLOCK
+#define ECHOCARD_HAS_ADAT      FALSE
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+#define ECHOCARD_HAS_MIDI
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 8 */
+#define PX_DIGITAL_OUT 8       /* 0 */
+#define PX_ANALOG_IN   8       /* 2 */
+#define PX_DIGITAL_IN  10      /* 2 */
+#define PX_NUM         12
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 2 */
+#define BX_DIGITAL_OUT 2       /* 2 */
+#define BX_ANALOG_IN   4       /* 2 */
+#define BX_DIGITAL_IN  6       /* 2 */
+#define BX_NUM         8
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_361_LOADER  0
+#define FW_MIA_DSP     1
+
+static const struct firmware card_fw[] = {
+       {0, "loader_dsp.fw"},
+       {0, "mia_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0},      /* DSP 56361 Mia rev.0 */
+       {0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0},      /* DSP 56361 Mia rev.1 */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_32000 |
+                       SNDRV_PCM_RATE_44100 |
+                       SNDRV_PCM_RATE_48000 |
+                       SNDRV_PCM_RATE_88200 |
+                       SNDRV_PCM_RATE_96000,
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 1,
+       .channels_max = 8,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+       /* One page (4k) contains 512 instructions. I don't know if the hw
+       supports lists longer than this. In this case periods_max=220 is a
+       safe limit to make sure the list never exceeds 512 instructions. */
+};
+
+
+#include "mia_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
+#include "midi.c"
diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c
new file mode 100644 (file)
index 0000000..891c705
--- /dev/null
@@ -0,0 +1,229 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int set_input_clock(struct echoaudio *chip, u16 clock);
+static int set_professional_spdif(struct echoaudio *chip, char prof);
+static int update_flags(struct echoaudio *chip);
+static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
+                          int gain);
+static int update_vmixer_level(struct echoaudio *chip);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Mia\n"));
+       snd_assert((subdevice_id & 0xfff0) == MIA, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->dsp_code_to_load = &card_fw[FW_MIA_DSP];
+       /* Since this card has no ASIC, mark it as loaded so everything
+          works OK */
+       chip->asic_loaded = TRUE;
+       if ((subdevice_id & 0x0000f) == MIA_MIDI_REV)
+               chip->has_midi = TRUE;
+       chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
+               ECHO_CLOCK_BIT_SPDIF;
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)))
+               return err;
+
+       /* Default routing of the virtual channels: vchannels 0-3 go to analog
+       outputs and vchannels 4-7 go to S/PDIF outputs */
+       set_vmixer_gain(chip, 0, 0, 0);
+       set_vmixer_gain(chip, 1, 1, 0);
+       set_vmixer_gain(chip, 0, 2, 0);
+       set_vmixer_gain(chip, 1, 3, 0);
+       set_vmixer_gain(chip, 2, 4, 0);
+       set_vmixer_gain(chip, 3, 5, 0);
+       set_vmixer_gain(chip, 2, 6, 0);
+       set_vmixer_gain(chip, 3, 7, 0);
+       err = update_vmixer_level(chip);
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       u32 clocks_from_dsp, clock_bits;
+
+       /* Map the DSP clock detect bits to the generic driver clock
+          detect bits */
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       clock_bits = ECHO_CLOCK_BIT_INTERNAL;
+
+       if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
+               clock_bits |= ECHO_CLOCK_BIT_SPDIF;
+
+       return clock_bits;
+}
+
+
+
+/* The Mia has no ASIC. Just do nothing */
+static int load_asic(struct echoaudio *chip)
+{
+       return 0;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u32 control_reg;
+
+       switch (rate) {
+       case 96000:
+               control_reg = MIA_96000;
+               break;
+       case 88200:
+               control_reg = MIA_88200;
+               break;
+       case 48000:
+               control_reg = MIA_48000;
+               break;
+       case 44100:
+               control_reg = MIA_44100;
+               break;
+       case 32000:
+               control_reg = MIA_32000;
+               break;
+       default:
+               DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+               return -EINVAL;
+       }
+
+       /* Override the clock setting if this Mia is set to S/PDIF clock */
+       if (chip->input_clock == ECHO_CLOCK_SPDIF)
+               control_reg |= MIA_SPDIF;
+
+       /* Set the control register if it has changed */
+       if (control_reg != le32_to_cpu(chip->comm_page->control_register)) {
+               if (wait_handshake(chip))
+                       return -EIO;
+
+               chip->comm_page->sample_rate = cpu_to_le32(rate);       /* ignored by the DSP */
+               chip->comm_page->control_register = cpu_to_le32(control_reg);
+               chip->sample_rate = rate;
+
+               clear_handshake(chip);
+               return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
+       }
+       return 0;
+}
+
+
+
+static int set_input_clock(struct echoaudio *chip, u16 clock)
+{
+       DE_ACT(("set_input_clock(%d)\n", clock));
+       snd_assert(clock == ECHO_CLOCK_INTERNAL || clock == ECHO_CLOCK_SPDIF,
+                  return -EINVAL);
+
+       chip->input_clock = clock;
+       return set_sample_rate(chip, chip->sample_rate);
+}
+
+
+
+/* This function routes the sound from a virtual channel to a real output */
+static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
+                          int gain)
+{
+       int index;
+
+       snd_assert(pipe < num_pipes_out(chip) &&
+                  output < num_busses_out(chip), return -EINVAL);
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       chip->vmixer_gain[output][pipe] = gain;
+       index = output * num_pipes_out(chip) + pipe;
+       chip->comm_page->vmixer[index] = gain;
+
+       DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+       return 0;
+}
+
+
+
+/* Tell the DSP to read and update virtual mixer levels in comm page. */
+static int update_vmixer_level(struct echoaudio *chip)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
+}
+
+
+
+/* Tell the DSP to reread the flags from the comm page */
+static int update_flags(struct echoaudio *chip)
+{
+       if (wait_handshake(chip))
+               return -EIO;
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_UPDATE_FLAGS);
+}
+
+
+
+static int set_professional_spdif(struct echoaudio *chip, char prof)
+{
+       DE_ACT(("set_professional_spdif %d\n", prof));
+       if (prof)
+               chip->comm_page->flags |=
+                       __constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+       else
+               chip->comm_page->flags &=
+                       ~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+       chip->professional_spdif = prof;
+       return update_flags(chip);
+}
+
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
new file mode 100644 (file)
index 0000000..e31f0f1
--- /dev/null
@@ -0,0 +1,327 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+/******************************************************************************
+       MIDI lowlevel code
+******************************************************************************/
+
+/* Start and stop Midi input */
+static int enable_midi_input(struct echoaudio *chip, char enable)
+{
+       DE_MID(("enable_midi_input(%d)\n", enable));
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       if (enable) {
+               chip->mtc_state = MIDI_IN_STATE_NORMAL;
+               chip->comm_page->flags |=
+                       __constant_cpu_to_le32(DSP_FLAG_MIDI_INPUT);
+       } else
+               chip->comm_page->flags &=
+                       ~__constant_cpu_to_le32(DSP_FLAG_MIDI_INPUT);
+
+       clear_handshake(chip);
+       return send_vector(chip, DSP_VC_UPDATE_FLAGS);
+}
+
+
+
+/* Send a buffer full of MIDI data to the DSP
+Returns how many actually written or < 0 on error */
+static int write_midi(struct echoaudio *chip, u8 *data, int bytes)
+{
+       snd_assert(bytes > 0 && bytes < MIDI_OUT_BUFFER_SIZE, return -EINVAL);
+
+       if (wait_handshake(chip))
+               return -EIO;
+
+       /* HF4 indicates that it is safe to write MIDI output data */
+       if (! (get_dsp_register(chip, CHI32_STATUS_REG) & CHI32_STATUS_REG_HF4))
+               return 0;
+
+       chip->comm_page->midi_output[0] = bytes;
+       memcpy(&chip->comm_page->midi_output[1], data, bytes);
+       chip->comm_page->midi_out_free_count = 0;
+       clear_handshake(chip);
+       send_vector(chip, DSP_VC_MIDI_WRITE);
+       DE_MID(("write_midi: %d\n", bytes));
+       return bytes;
+}
+
+
+
+/* Run the state machine for MIDI input data
+MIDI time code sync isn't supported by this code right now, but you still need
+this state machine to parse the incoming MIDI data stream.  Every time the DSP
+sees a 0xF1 byte come in, it adds the DSP sample position to the MIDI data
+stream. The DSP sample position is represented as a 32 bit unsigned value,
+with the high 16 bits first, followed by the low 16 bits. Since these aren't
+real MIDI bytes, the following logic is needed to skip them. */
+static inline int mtc_process_data(struct echoaudio *chip, short midi_byte)
+{
+       switch (chip->mtc_state) {
+       case MIDI_IN_STATE_NORMAL:
+               if (midi_byte == 0xF1)
+                       chip->mtc_state = MIDI_IN_STATE_TS_HIGH;
+               break;
+       case MIDI_IN_STATE_TS_HIGH:
+               chip->mtc_state = MIDI_IN_STATE_TS_LOW;
+               return MIDI_IN_SKIP_DATA;
+               break;
+       case MIDI_IN_STATE_TS_LOW:
+               chip->mtc_state = MIDI_IN_STATE_F1_DATA;
+               return MIDI_IN_SKIP_DATA;
+               break;
+       case MIDI_IN_STATE_F1_DATA:
+               chip->mtc_state = MIDI_IN_STATE_NORMAL;
+               break;
+       }
+       return 0;
+}
+
+
+
+/* This function is called from the IRQ handler and it reads the midi data
+from the DSP's buffer.  It returns the number of bytes received. */
+static int midi_service_irq(struct echoaudio *chip)
+{
+       short int count, midi_byte, i, received;
+
+       /* The count is at index 0, followed by actual data */
+       count = le16_to_cpu(chip->comm_page->midi_input[0]);
+
+       snd_assert(count < MIDI_IN_BUFFER_SIZE, return 0);
+
+       /* Get the MIDI data from the comm page */
+       i = 1;
+       received = 0;
+       for (i = 1; i <= count; i++) {
+               /* Get the MIDI byte */
+               midi_byte = le16_to_cpu(chip->comm_page->midi_input[i]);
+
+               /* Parse the incoming MIDI stream. The incoming MIDI data
+               consists of MIDI bytes and timestamps for the MIDI time code
+               0xF1 bytes. mtc_process_data() is a little state machine that
+               parses the stream. If you get MIDI_IN_SKIP_DATA back, then
+               this is a timestamp byte, not a MIDI byte, so don't store it
+               in the MIDI input buffer. */
+               if (mtc_process_data(chip, midi_byte) == MIDI_IN_SKIP_DATA)
+                       continue;
+
+               chip->midi_buffer[received++] = (u8)midi_byte;
+       }
+
+       return received;
+}
+
+
+
+
+/******************************************************************************
+       MIDI interface
+******************************************************************************/
+
+static int snd_echo_midi_input_open(struct snd_rawmidi_substream *substream)
+{
+       struct echoaudio *chip = substream->rmidi->private_data;
+
+       chip->midi_in = substream;
+       DE_MID(("rawmidi_iopen\n"));
+       return 0;
+}
+
+
+
+static void snd_echo_midi_input_trigger(struct snd_rawmidi_substream *substream,
+                                       int up)
+{
+       struct echoaudio *chip = substream->rmidi->private_data;
+
+       if (up != chip->midi_input_enabled) {
+               spin_lock_irq(&chip->lock);
+               enable_midi_input(chip, up);
+               spin_unlock_irq(&chip->lock);
+               chip->midi_input_enabled = up;
+       }
+}
+
+
+
+static int snd_echo_midi_input_close(struct snd_rawmidi_substream *substream)
+{
+       struct echoaudio *chip = substream->rmidi->private_data;
+
+       chip->midi_in = NULL;
+       DE_MID(("rawmidi_iclose\n"));
+       return 0;
+}
+
+
+
+static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream)
+{
+       struct echoaudio *chip = substream->rmidi->private_data;
+
+       chip->tinuse = 0;
+       chip->midi_full = 0;
+       chip->midi_out = substream;
+       DE_MID(("rawmidi_oopen\n"));
+       return 0;
+}
+
+
+
+static void snd_echo_midi_output_write(unsigned long data)
+{
+       struct echoaudio *chip = (struct echoaudio *)data;
+       unsigned long flags;
+       int bytes, sent, time;
+       unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1];
+
+       DE_MID(("snd_echo_midi_output_write\n"));
+       /* No interrupts are involved: we have to check at regular intervals
+       if the card's output buffer has room for new data. */
+       sent = bytes = 0;
+       spin_lock_irqsave(&chip->lock, flags);
+       chip->midi_full = 0;
+       if (chip->midi_out && !snd_rawmidi_transmit_empty(chip->midi_out)) {
+               bytes = snd_rawmidi_transmit_peek(chip->midi_out, buf,
+                                                 MIDI_OUT_BUFFER_SIZE - 1);
+               DE_MID(("Try to send %d bytes...\n", bytes));
+               sent = write_midi(chip, buf, bytes);
+               if (sent < 0) {
+                       snd_printk(KERN_ERR "write_midi() error %d\n", sent);
+                       /* retry later */
+                       sent = 9000;
+                       chip->midi_full = 1;
+               } else if (sent > 0) {
+                       DE_MID(("%d bytes sent\n", sent));
+                       snd_rawmidi_transmit_ack(chip->midi_out, sent);
+               } else {
+                       /* Buffer is full. DSP's internal buffer is 64 (128 ?)
+                       bytes long. Let's wait until half of them are sent */
+                       DE_MID(("Full\n"));
+                       sent = 32;
+                       chip->midi_full = 1;
+               }
+       }
+
+       /* We restart the timer only if there is some data left to send */
+       if (!snd_rawmidi_transmit_empty(chip->midi_out) && chip->tinuse) {
+               /* The timer will expire slightly after the data has been
+                  sent */
+               time = (sent << 3) / 25 + 1;    /* 8/25=0.32ms to send a byte */
+               mod_timer(&chip->timer, jiffies + (time * HZ + 999) / 1000);
+               DE_MID(("Timer armed(%d)\n", ((time * HZ + 999) / 1000)));
+       }
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+
+
+static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream,
+                                        int up)
+{
+       struct echoaudio *chip = substream->rmidi->private_data;
+
+       DE_MID(("snd_echo_midi_output_trigger(%d)\n", up));
+       spin_lock_irq(&chip->lock);
+       if (up) {
+               if (!chip->tinuse) {
+                       init_timer(&chip->timer);
+                       chip->timer.function = snd_echo_midi_output_write;
+                       chip->timer.data = (unsigned long)chip;
+                       chip->tinuse = 1;
+               }
+       } else {
+               if (chip->tinuse) {
+                       del_timer(&chip->timer);
+                       chip->tinuse = 0;
+                       DE_MID(("Timer removed\n"));
+               }
+       }
+       spin_unlock_irq(&chip->lock);
+
+       if (up && !chip->midi_full)
+               snd_echo_midi_output_write((unsigned long)chip);
+}
+
+
+
+static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream)
+{
+       struct echoaudio *chip = substream->rmidi->private_data;
+
+       chip->midi_out = NULL;
+       DE_MID(("rawmidi_oclose\n"));
+       return 0;
+}
+
+
+
+static struct snd_rawmidi_ops snd_echo_midi_input = {
+       .open = snd_echo_midi_input_open,
+       .close = snd_echo_midi_input_close,
+       .trigger = snd_echo_midi_input_trigger,
+};
+
+static struct snd_rawmidi_ops snd_echo_midi_output = {
+       .open = snd_echo_midi_output_open,
+       .close = snd_echo_midi_output_close,
+       .trigger = snd_echo_midi_output_trigger,
+};
+
+
+
+/* <--snd_echo_probe() */
+static int __devinit snd_echo_midi_create(struct snd_card *card,
+                                         struct echoaudio *chip)
+{
+       int err;
+
+       if ((err = snd_rawmidi_new(card, card->shortname, 0, 1, 1,
+                                  &chip->rmidi)) < 0)
+               return err;
+
+       strcpy(chip->rmidi->name, card->shortname);
+       chip->rmidi->private_data = chip;
+
+       snd_rawmidi_set_ops(chip->rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+                           &snd_echo_midi_input);
+       snd_rawmidi_set_ops(chip->rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+                           &snd_echo_midi_output);
+
+       chip->rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
+               SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
+       DE_INIT(("MIDI ok\n"));
+       return 0;
+}
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c
new file mode 100644 (file)
index 0000000..5dc512a
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *  ALSA driver for Echoaudio soundcards.
+ *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define ECHO24_FAMILY
+#define ECHOCARD_MONA
+#define ECHOCARD_NAME "Mona"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_ASIC
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_DIGITAL_IO
+#define ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
+#define ECHOCARD_HAS_DIGITAL_MODE_SWITCH
+#define ECHOCARD_HAS_EXTERNAL_CLOCK
+#define ECHOCARD_HAS_ADAT      6
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT  0       /* 6 */
+#define PX_DIGITAL_OUT 6       /* 8 */
+#define PX_ANALOG_IN   14      /* 4 */
+#define PX_DIGITAL_IN  18      /* 8 */
+#define PX_NUM         26
+
+/* Bus indexes */
+#define BX_ANALOG_OUT  0       /* 6 */
+#define BX_DIGITAL_OUT 6       /* 8 */
+#define BX_ANALOG_IN   14      /* 4 */
+#define BX_DIGITAL_IN  18      /* 8 */
+#define BX_NUM         26
+
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+#define FW_361_LOADER          0
+#define FW_MONA_301_DSP                1
+#define FW_MONA_361_DSP                2
+#define FW_MONA_301_1_ASIC48   3
+#define FW_MONA_301_1_ASIC96   4
+#define FW_MONA_361_1_ASIC48   5
+#define FW_MONA_361_1_ASIC96   6
+#define FW_MONA_2_ASIC         7
+
+static const struct firmware card_fw[] = {
+       {0, "loader_dsp.fw"},
+       {0, "mona_301_dsp.fw"},
+       {0, "mona_361_dsp.fw"},
+       {0, "mona_301_1_asic_48.fw"},
+       {0, "mona_301_1_asic_96.fw"},
+       {0, "mona_361_1_asic_48.fw"},
+       {0, "mona_361_1_asic_96.fw"},
+       {0, "mona_2_asic.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+       {0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0},      /* DSP 56301 Mona rev.0 */
+       {0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0},      /* DSP 56301 Mona rev.1 */
+       {0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0},      /* DSP 56301 Mona rev.2 */
+       {0x1057, 0x3410, 0xECC0, 0x0070, 0, 0, 0},      /* DSP 56361 Mona rev.0 */
+       {0x1057, 0x3410, 0xECC0, 0x0071, 0, 0, 0},      /* DSP 56361 Mona rev.1 */
+       {0x1057, 0x3410, 0xECC0, 0x0072, 0, 0, 0},      /* DSP 56361 Mona rev.2 */
+       {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats =      SNDRV_PCM_FMTBIT_U8 |
+                       SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_3LE |
+                       SNDRV_PCM_FMTBIT_S32_LE |
+                       SNDRV_PCM_FMTBIT_S32_BE,
+       .rates =        SNDRV_PCM_RATE_8000_48000 |
+                       SNDRV_PCM_RATE_88200 |
+                       SNDRV_PCM_RATE_96000,
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 1,
+       .channels_max = 8,
+       .buffer_bytes_max = 262144,
+       .period_bytes_min = 32,
+       .period_bytes_max = 131072,
+       .periods_min = 2,
+       .periods_max = 220,
+       /* One page (4k) contains 512 instructions. I don't know if the hw
+       supports lists longer than this. In this case periods_max=220 is a
+       safe limit to make sure the list never exceeds 512 instructions. */
+};
+
+
+#include "mona_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio_gml.c"
+#include "echoaudio.c"
diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c
new file mode 100644 (file)
index 0000000..c0b4bf0
--- /dev/null
@@ -0,0 +1,428 @@
+/****************************************************************************
+
+   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
+   All rights reserved
+   www.echoaudio.com
+
+   This file is part of Echo Digital Audio's generic driver library.
+
+   Echo Digital Audio's generic driver library is free software;
+   you can redistribute it and/or modify it under the terms of
+   the GNU General Public License as published by the Free Software
+   Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA  02111-1307, USA.
+
+   *************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+****************************************************************************/
+
+
+static int write_control_reg(struct echoaudio *chip, u32 value, char force);
+static int set_input_clock(struct echoaudio *chip, u16 clock);
+static int set_professional_spdif(struct echoaudio *chip, char prof);
+static int set_digital_mode(struct echoaudio *chip, u8 mode);
+static int load_asic_generic(struct echoaudio *chip, u32 cmd,
+                            const struct firmware *asic);
+static int check_asic_status(struct echoaudio *chip);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+       int err;
+
+       DE_INIT(("init_hw() - Mona\n"));
+       snd_assert((subdevice_id & 0xfff0) == MONA, return -ENODEV);
+
+       if ((err = init_dsp_comm_page(chip))) {
+               DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+               return err;
+       }
+
+       chip->device_id = device_id;
+       chip->subdevice_id = subdevice_id;
+       chip->bad_board = TRUE;
+       chip->input_clock_types =
+               ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
+               ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT;
+       chip->digital_modes =
+               ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
+               ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
+               ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
+
+       /* Mona comes in both '301 and '361 flavors */
+       if (chip->device_id == DEVICE_ID_56361)
+               chip->dsp_code_to_load = &card_fw[FW_MONA_361_DSP];
+       else
+               chip->dsp_code_to_load = &card_fw[FW_MONA_301_DSP];
+
+       chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
+       chip->professional_spdif = FALSE;
+       chip->digital_in_automute = TRUE;
+
+       if ((err = load_firmware(chip)) < 0)
+               return err;
+       chip->bad_board = FALSE;
+
+       if ((err = init_line_levels(chip)) < 0)
+               return err;
+
+       err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
+       snd_assert(err >= 0, return err);
+       err = set_professional_spdif(chip, TRUE);
+
+       DE_INIT(("init_hw done\n"));
+       return err;
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+       u32 clocks_from_dsp, clock_bits;
+
+       /* Map the DSP clock detect bits to the generic driver clock
+          detect bits */
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       clock_bits = ECHO_CLOCK_BIT_INTERNAL;
+
+       if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF)
+               clock_bits |= ECHO_CLOCK_BIT_SPDIF;
+
+       if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_ADAT)
+               clock_bits |= ECHO_CLOCK_BIT_ADAT;
+
+       if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_WORD)
+               clock_bits |= ECHO_CLOCK_BIT_WORD;
+
+       return clock_bits;
+}
+
+
+
+/* Mona has an ASIC on the PCI card and another ASIC in the external box; 
+both need to be loaded. */
+static int load_asic(struct echoaudio *chip)
+{
+       u32 control_reg;
+       int err;
+       const struct firmware *asic;
+
+       if (chip->asic_loaded)
+               return 0;
+
+       mdelay(10);
+
+       if (chip->device_id == DEVICE_ID_56361)
+               asic = &card_fw[FW_MONA_361_1_ASIC48];
+       else
+               asic = &card_fw[FW_MONA_301_1_ASIC48];
+
+       err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC, asic);
+       if (err < 0)
+               return err;
+
+       chip->asic_code = asic;
+       mdelay(10);
+
+       /* Do the external one */
+       err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_EXTERNAL_ASIC,
+                               &card_fw[FW_MONA_2_ASIC]);
+       if (err < 0)
+               return err;
+
+       mdelay(10);
+       err = check_asic_status(chip);
+
+       /* Set up the control register if the load succeeded -
+          48 kHz, internal clock, S/PDIF RCA mode */
+       if (!err) {
+               control_reg = GML_CONVERTER_ENABLE | GML_48KHZ;
+               err = write_control_reg(chip, control_reg, TRUE);
+       }
+
+       return err;
+}
+
+
+
+/* Depending on what digital mode you want, Mona needs different ASICs
+loaded.  This function checks the ASIC needed for the new mode and sees
+if it matches the one already loaded. */
+static int switch_asic(struct echoaudio *chip, char double_speed)
+{
+       const struct firmware *asic;
+       int err;
+
+       /* Check the clock detect bits to see if this is
+       a single-speed clock or a double-speed clock; load
+       a new ASIC if necessary. */
+       if (chip->device_id == DEVICE_ID_56361) {
+               if (double_speed)
+                       asic = &card_fw[FW_MONA_361_1_ASIC96];
+               else
+                       asic = &card_fw[FW_MONA_361_1_ASIC48];
+       } else {
+               if (double_speed)
+                       asic = &card_fw[FW_MONA_301_1_ASIC96];
+               else
+                       asic = &card_fw[FW_MONA_301_1_ASIC48];
+       }
+
+       if (asic != chip->asic_code) {
+               /* Load the desired ASIC */
+               err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
+                                       asic);
+               if (err < 0)
+                       return err;
+               chip->asic_code = asic;
+       }
+
+       return 0;
+}
+
+
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+       u32 control_reg, clock;
+       const struct firmware *asic;
+       char force_write;
+
+       /* Only set the clock for internal mode. */
+       if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
+               DE_ACT(("set_sample_rate: Cannot set sample rate - "
+                       "clock not set to CLK_CLOCKININTERNAL\n"));
+               /* Save the rate anyhow */
+               chip->comm_page->sample_rate = cpu_to_le32(rate);
+               chip->sample_rate = rate;
+               return 0;
+       }
+
+       /* Now, check to see if the required ASIC is loaded */
+       if (rate >= 88200) {
+               if (chip->digital_mode == DIGITAL_MODE_ADAT)
+                       return -EINVAL;
+               if (chip->device_id == DEVICE_ID_56361)
+                       asic = &card_fw[FW_MONA_361_1_ASIC96];
+               else
+                       asic = &card_fw[FW_MONA_301_1_ASIC96];
+       } else {
+               if (chip->device_id == DEVICE_ID_56361)
+                       asic = &card_fw[FW_MONA_361_1_ASIC48];
+               else
+                       asic = &card_fw[FW_MONA_301_1_ASIC48];
+       }
+
+       force_write = 0;
+       if (asic != chip->asic_code) {
+               int err;
+               /* Load the desired ASIC (load_asic_generic() can sleep) */
+               spin_unlock_irq(&chip->lock);
+               err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC,
+                                       asic);
+               spin_lock_irq(&chip->lock);
+
+               if (err < 0)
+                       return err;
+               chip->asic_code = asic;
+               force_write = 1;
+       }
+
+       /* Compute the new control register value */
+       clock = 0;
+       control_reg = le32_to_cpu(chip->comm_page->control_register);
+       control_reg &= GML_CLOCK_CLEAR_MASK;
+       control_reg &= GML_SPDIF_RATE_CLEAR_MASK;
+
+       switch (rate) {
+       case 96000:
+               clock = GML_96KHZ;
+               break;
+       case 88200:
+               clock = GML_88KHZ;
+               break;
+       case 48000:
+               clock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
+               break;
+       case 44100:
+               clock = GML_44KHZ;
+               /* Professional mode */
+               if (control_reg & GML_SPDIF_PRO_MODE)
+                       clock |= GML_SPDIF_SAMPLE_RATE0;
+               break;
+       case 32000:
+               clock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 |
+                       GML_SPDIF_SAMPLE_RATE1;
+               break;
+       case 22050:
+               clock = GML_22KHZ;
+               break;
+       case 16000:
+               clock = GML_16KHZ;
+               break;
+       case 11025:
+               clock = GML_11KHZ;
+               break;
+       case 8000:
+               clock = GML_8KHZ;
+               break;
+       default:
+               DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+               return -EINVAL;
+       }
+
+       control_reg |= clock;
+
+       chip->comm_page->sample_rate = cpu_to_le32(rate);       /* ignored by the DSP */
+       chip->sample_rate = rate;
+       DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+
+       return write_control_reg(chip, control_reg, force_write);
+}
+
+
+
+static int set_input_clock(struct echoaudio *chip, u16 clock)
+{
+       u32 control_reg, clocks_from_dsp;
+       int err;
+
+       DE_ACT(("set_input_clock:\n"));
+
+       /* Prevent two simultaneous calls to switch_asic() */
+       if (atomic_read(&chip->opencount))
+               return -EAGAIN;
+
+       /* Mask off the clock select bits */
+       control_reg = le32_to_cpu(chip->comm_page->control_register) &
+               GML_CLOCK_CLEAR_MASK;
+       clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
+
+       switch (clock) {
+       case ECHO_CLOCK_INTERNAL:
+               DE_ACT(("Set Mona clock to INTERNAL\n"));
+               chip->input_clock = ECHO_CLOCK_INTERNAL;
+               return set_sample_rate(chip, chip->sample_rate);
+       case ECHO_CLOCK_SPDIF:
+               if (chip->digital_mode == DIGITAL_MODE_ADAT)
+                       return -EAGAIN;
+               spin_unlock_irq(&chip->lock);
+               err = switch_asic(chip, clocks_from_dsp &
+                                 GML_CLOCK_DETECT_BIT_SPDIF96);
+               spin_lock_irq(&chip->lock);
+               if (err < 0)
+                       return err;
+               DE_ACT(("Set Mona clock to SPDIF\n"));
+               control_reg |= GML_SPDIF_CLOCK;
+               if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96)
+                       control_reg |= GML_DOUBLE_SPEED_MODE;
+               else
+                       control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               break;
+       case ECHO_CLOCK_WORD:
+               DE_ACT(("Set Mona clock to WORD\n"));
+               spin_unlock_irq(&chip->lock);
+               err = switch_asic(chip, clocks_from_dsp &
+                                 GML_CLOCK_DETECT_BIT_WORD96);
+               spin_lock_irq(&chip->lock);
+               if (err < 0)
+                       return err;
+               control_reg |= GML_WORD_CLOCK;
+               if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_WORD96)
+                       control_reg |= GML_DOUBLE_SPEED_MODE;
+               else
+                       control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               break;
+       case ECHO_CLOCK_ADAT:
+               DE_ACT(("Set Mona clock to ADAT\n"));
+               if (chip->digital_mode != DIGITAL_MODE_ADAT)
+                       return -EAGAIN;
+               control_reg |= GML_ADAT_CLOCK;
+               control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               break;
+       default:
+               DE_ACT(("Input clock 0x%x not supported for Mona\n", clock));
+               return -EINVAL;
+       }
+
+       chip->input_clock = clock;
+       return write_control_reg(chip, control_reg, TRUE);
+}
+
+
+
+static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
+{
+       u32 control_reg;
+       int err, incompatible_clock;
+
+       /* Set clock to "internal" if it's not compatible with the new mode */
+       incompatible_clock = FALSE;
+       switch (mode) {
+       case DIGITAL_MODE_SPDIF_OPTICAL:
+       case DIGITAL_MODE_SPDIF_RCA:
+               if (chip->input_clock == ECHO_CLOCK_ADAT)
+                       incompatible_clock = TRUE;
+               break;
+       case DIGITAL_MODE_ADAT:
+               if (chip->input_clock == ECHO_CLOCK_SPDIF)
+                       incompatible_clock = TRUE;
+               break;
+       default:
+               DE_ACT(("Digital mode not supported: %d\n", mode));
+               return -EINVAL;
+       }
+
+       spin_lock_irq(&chip->lock);
+
+       if (incompatible_clock) {       /* Switch to 48KHz, internal */
+               chip->sample_rate = 48000;
+               set_input_clock(chip, ECHO_CLOCK_INTERNAL);
+       }
+
+       /* Clear the current digital mode */
+       control_reg = le32_to_cpu(chip->comm_page->control_register);
+       control_reg &= GML_DIGITAL_MODE_CLEAR_MASK;
+
+       /* Tweak the control reg */
+       switch (mode) {
+       case DIGITAL_MODE_SPDIF_OPTICAL:
+               control_reg |= GML_SPDIF_OPTICAL_MODE;
+               break;
+       case DIGITAL_MODE_SPDIF_RCA:
+               /* GML_SPDIF_OPTICAL_MODE bit cleared */
+               break;
+       case DIGITAL_MODE_ADAT:
+               /* If the current ASIC is the 96KHz ASIC, switch the ASIC
+                  and set to 48 KHz */
+               if (chip->asic_code == &card_fw[FW_MONA_361_1_ASIC96] ||
+                   chip->asic_code == &card_fw[FW_MONA_301_1_ASIC96]) {
+                       set_sample_rate(chip, 48000);
+               }
+               control_reg |= GML_ADAT_MODE;
+               control_reg &= ~GML_DOUBLE_SPEED_MODE;
+               break;
+       }
+
+       err = write_control_reg(chip, control_reg, FALSE);
+       spin_unlock_irq(&chip->lock);
+       if (err < 0)
+               return err;
+       chip->digital_mode = mode;
+
+       DE_ACT(("set_digital_mode to %d\n", mode));
+       return incompatible_clock;
+}
index 8c2a8174ece182a24f8a0ee2ae6535cb98b73a67..23201f3eeb1293ccc958a81e30e85ad81fc49d19 100644 (file)
@@ -408,7 +408,9 @@ static const struct hda_codec_preset *find_codec_preset(struct hda_codec *codec)
                        u32 mask = preset->mask;
                        if (! mask)
                                mask = ~0;
-                       if (preset->id == (codec->vendor_id & mask))
+                       if (preset->id == (codec->vendor_id & mask) &&
+                           (! preset->rev ||
+                            preset->rev == codec->revision_id))
                                return preset;
                }
        }
index dd4e00a82b55fdd79eb7f7a08182f193f85dd724..33b7d580646923f91a3892b8803cfa585ff2846e 100644 (file)
@@ -799,6 +799,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = {
        { .pci_subvendor = 0x1043, .pci_subdevice = 0x818f,
          .config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */
        { .modelname = "laptop-eapd",   .config = AD1986A_LAPTOP_EAPD },
+       { .pci_subvendor = 0x144d, .pci_subdevice = 0xc023,
+         .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */
        { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024,
          .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */
        { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153,
index 98b9f16c26ffa633d016294e1c47f63f073d3408..18d105263feae7795bf965424bb3c5c81df13037 100644 (file)
@@ -78,6 +78,7 @@ enum {
 enum {
        ALC262_BASIC,
        ALC262_FUJITSU,
+       ALC262_HP_BPC,
        ALC262_AUTO,
        ALC262_MODEL_LAST /* last tag */
 };
@@ -85,6 +86,7 @@ enum {
 /* ALC861 models */
 enum {
        ALC861_3ST,
+       ALC660_3ST,
        ALC861_3ST_DIG,
        ALC861_6ST_DIG,
        ALC861_AUTO,
@@ -99,6 +101,17 @@ enum {
        ALC882_MODEL_LAST,
 };
 
+/* ALC883 models */
+enum {
+       ALC883_3ST_2ch_DIG,
+       ALC883_3ST_6ch_DIG,
+       ALC883_3ST_6ch,
+       ALC883_6ST_DIG,
+       ALC888_DEMO_BOARD,
+       ALC883_AUTO,
+       ALC883_MODEL_LAST,
+};
+
 /* for GPIO Poll */
 #define GPIO_MASK      0x03
 
@@ -108,7 +121,8 @@ struct alc_spec {
        unsigned int num_mixers;
 
        const struct hda_verb *init_verbs[5];   /* initialization verbs
-                                                * don't forget NULL termination!
+                                                * don't forget NULL
+                                                * termination!
                                                 */
        unsigned int num_init_verbs;
 
@@ -163,7 +177,9 @@ struct alc_spec {
  * configuration template - to be copied to the spec instance
  */
 struct alc_config_preset {
-       struct snd_kcontrol_new *mixers[5]; /* should be identical size with spec */
+       struct snd_kcontrol_new *mixers[5]; /* should be identical size
+                                            * with spec
+                                            */
        const struct hda_verb *init_verbs[5];
        unsigned int num_dacs;
        hda_nid_t *dac_nids;
@@ -184,7 +200,8 @@ struct alc_config_preset {
 /*
  * input MUX handling
  */
-static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_info *uinfo)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
@@ -194,7 +211,8 @@ static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
        return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
 }
 
-static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
@@ -204,21 +222,24 @@ static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
        return 0;
 }
 
-static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
        return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
-                                    spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
+                                    spec->adc_nids[adc_idx],
+                                    &spec->cur_mux[adc_idx]);
 }
 
 
 /*
  * channel mode setting
  */
-static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
@@ -226,20 +247,24 @@ static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_i
                                    spec->num_channel_mode);
 }
 
-static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
        return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
-                                  spec->num_channel_mode, spec->multiout.max_channels);
+                                  spec->num_channel_mode,
+                                  spec->multiout.max_channels);
 }
 
-static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
        return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
-                                  spec->num_channel_mode, &spec->multiout.max_channels);
+                                  spec->num_channel_mode,
+                                  &spec->multiout.max_channels);
 }
 
 /*
@@ -290,7 +315,8 @@ static signed char alc_pin_mode_dir_info[5][2] = {
 #define alc_pin_mode_n_items(_dir) \
        (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
 
-static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_info *uinfo)
 {
        unsigned int item_num = uinfo->value.enumerated.item;
        unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
@@ -305,40 +331,46 @@ static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
        return 0;
 }
 
-static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
 {
        unsigned int i;
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = kcontrol->private_value & 0xffff;
        unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
        long *valp = ucontrol->value.integer.value;
-       unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
+       unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
+                                                AC_VERB_GET_PIN_WIDGET_CONTROL,
+                                                0x00);
 
        /* Find enumerated value for current pinctl setting */
        i = alc_pin_mode_min(dir);
-       while (alc_pin_mode_values[i]!=pinctl && i<=alc_pin_mode_max(dir))
+       while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
                i++;
-       *valp = i<=alc_pin_mode_max(dir)?i:alc_pin_mode_min(dir);
+       *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
        return 0;
 }
 
-static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
 {
        signed int change;
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = kcontrol->private_value & 0xffff;
        unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
        long val = *ucontrol->value.integer.value;
-       unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
+       unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
+                                                AC_VERB_GET_PIN_WIDGET_CONTROL,
+                                                0x00);
 
-       if (val<alc_pin_mode_min(dir) || val>alc_pin_mode_max(dir)) 
+       if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir)) 
                val = alc_pin_mode_min(dir);
 
        change = pinctl != alc_pin_mode_values[val];
        if (change) {
                /* Set pin mode to that requested */
                snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL,
-                       alc_pin_mode_values[val]);
+                                   alc_pin_mode_values[val]);
 
                /* Also enable the retasking pin's input/output as required 
                 * for the requested pin mode.  Enum values of 2 or less are
@@ -351,15 +383,19 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
                 * this turns out to be necessary in the future.
                 */
                if (val <= 2) {
-                       snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
-                               AMP_OUT_MUTE);
-                       snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
-                               AMP_IN_UNMUTE(0));
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_OUT_MUTE);
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_IN_UNMUTE(0));
                } else {
-                       snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
-                               AMP_IN_MUTE(0));
-                       snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
-                               AMP_OUT_UNMUTE);
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_IN_MUTE(0));
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_OUT_UNMUTE);
                }
        }
        return change;
@@ -378,7 +414,8 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
  * needed for any "production" models.
  */
 #ifdef CONFIG_SND_DEBUG
-static int alc_gpio_data_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int alc_gpio_data_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
 {
        uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
        uinfo->count = 1;
@@ -386,33 +423,38 @@ static int alc_gpio_data_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
        uinfo->value.integer.max = 1;
        return 0;
 }                                
-static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = kcontrol->private_value & 0xffff;
        unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
        long *valp = ucontrol->value.integer.value;
-       unsigned int val = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_GPIO_DATA,0x00);
+       unsigned int val = snd_hda_codec_read(codec, nid, 0,
+                                             AC_VERB_GET_GPIO_DATA, 0x00);
 
        *valp = (val & mask) != 0;
        return 0;
 }
-static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
 {
        signed int change;
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = kcontrol->private_value & 0xffff;
        unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
        long val = *ucontrol->value.integer.value;
-       unsigned int gpio_data = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_GPIO_DATA,0x00);
+       unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
+                                                   AC_VERB_GET_GPIO_DATA,
+                                                   0x00);
 
        /* Set/unset the masked GPIO bit(s) as needed */
-       change = (val==0?0:mask) != (gpio_data & mask);
-       if (val==0)
+       change = (val == 0 ? 0 : mask) != (gpio_data & mask);
+       if (val == 0)
                gpio_data &= ~mask;
        else
                gpio_data |= mask;
-       snd_hda_codec_write(codec,nid,0,AC_VERB_SET_GPIO_DATA,gpio_data);
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data);
 
        return change;
 }
@@ -432,7 +474,8 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
  * necessary.
  */
 #ifdef CONFIG_SND_DEBUG
-static int alc_spdif_ctrl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int alc_spdif_ctrl_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
 {
        uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
        uinfo->count = 1;
@@ -440,33 +483,39 @@ static int alc_spdif_ctrl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
        uinfo->value.integer.max = 1;
        return 0;
 }                                
-static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = kcontrol->private_value & 0xffff;
        unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
        long *valp = ucontrol->value.integer.value;
-       unsigned int val = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_DIGI_CONVERT,0x00);
+       unsigned int val = snd_hda_codec_read(codec, nid, 0,
+                                             AC_VERB_GET_DIGI_CONVERT, 0x00);
 
        *valp = (val & mask) != 0;
        return 0;
 }
-static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
 {
        signed int change;
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = kcontrol->private_value & 0xffff;
        unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
        long val = *ucontrol->value.integer.value;
-       unsigned int ctrl_data = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_DIGI_CONVERT,0x00);
+       unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
+                                                   AC_VERB_GET_DIGI_CONVERT,
+                                                   0x00);
 
        /* Set/unset the masked control bit(s) as needed */
-       change = (val==0?0:mask) != (ctrl_data & mask);
+       change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
        if (val==0)
                ctrl_data &= ~mask;
        else
                ctrl_data |= mask;
-       snd_hda_codec_write(codec,nid,0,AC_VERB_SET_DIGI_CONVERT_1,ctrl_data);
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+                           ctrl_data);
 
        return change;
 }
@@ -481,14 +530,17 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
 /*
  * set up from the preset table
  */
-static void setup_preset(struct alc_spec *spec, const struct alc_config_preset *preset)
+static void setup_preset(struct alc_spec *spec,
+                        const struct alc_config_preset *preset)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
                spec->mixers[spec->num_mixers++] = preset->mixers[i];
-       for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; i++)
-               spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i];
+       for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
+            i++)
+               spec->init_verbs[spec->num_init_verbs++] =
+                       preset->init_verbs[i];
        
        spec->channel_mode = preset->channel_mode;
        spec->num_channel_mode = preset->num_channel_mode;
@@ -517,8 +569,8 @@ static void setup_preset(struct alc_spec *spec, const struct alc_config_preset *
  * ALC880 3-stack model
  *
  * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
- * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b
- *                 HP = 0x19
+ * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
+ *                 F-Mic = 0x1b, HP = 0x19
  */
 
 static hda_nid_t alc880_dac_nids[4] = {
@@ -662,7 +714,8 @@ static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
 /*
  * ALC880 5-stack model
  *
- * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), Side = 0x02 (0xd)
+ * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
+ *      Side = 0x02 (0xd)
  * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
  *                 Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
  */
@@ -700,7 +753,8 @@ static struct hda_channel_mode alc880_fivestack_modes[2] = {
 /*
  * ALC880 6-stack model
  *
- * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), Side = 0x05 (0x0f)
+ * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
+ *      Side = 0x05 (0x0f)
  * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
  *   Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
  */
@@ -811,7 +865,8 @@ static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
  * Z710V model
  *
  * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
- * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), Line = 0x1a
+ * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
+ *                 Line = 0x1a
  */
 
 static hda_nid_t alc880_z71v_dac_nids[1] = {
@@ -966,7 +1021,8 @@ static int alc_build_controls(struct hda_codec *codec)
        }
 
        if (spec->multiout.dig_out_nid) {
-               err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+               err = snd_hda_create_spdif_out_ctls(codec,
+                                                   spec->multiout.dig_out_nid);
                if (err < 0)
                        return err;
        }
@@ -999,8 +1055,8 @@ static struct hda_verb alc880_volume_init_verbs[] = {
 
        /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
         * mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for front panel
-        * mic (mic 2)
+        * Note: PASD motherboards uses the Line In 2 as the input for front
+        * panel mic (mic 2)
         */
        /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1154,8 +1210,8 @@ static struct hda_verb alc880_pin_z71v_init_verbs[] = {
 
 /*
  * 6-stack pin configuration:
- * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19,
- * line = 0x1a, HP = 0x1b
+ * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
+ * f-mic = 0x19, line = 0x1a, HP = 0x1b
  */
 static struct hda_verb alc880_pin_6stack_init_verbs[] = {
        {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
@@ -1587,8 +1643,8 @@ static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                       struct snd_pcm_substream *substream)
 {
        struct alc_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
-                                               format, substream);
+       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+                                               stream_tag, format, substream);
 }
 
 static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
@@ -1640,7 +1696,8 @@ static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 {
        struct alc_spec *spec = codec->spec;
 
-       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
+       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+                                  0, 0, 0);
        return 0;
 }
 
@@ -1822,7 +1879,8 @@ static struct hda_channel_mode alc880_test_modes[4] = {
        { 8, NULL },
 };
 
-static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = {
                "N/A", "Line Out", "HP Out",
@@ -1837,7 +1895,8 @@ static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        return 0;
 }
 
-static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
@@ -1863,7 +1922,8 @@ static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_el
        return 0;
 }
 
-static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
@@ -1881,15 +1941,18 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
                                     AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
        new_ctl = ctls[ucontrol->value.enumerated.item[0]];
        if (old_ctl != new_ctl) {
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl);
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl);
                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                                   ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000);
+                                   (ucontrol->value.enumerated.item[0] >= 3 ?
+                                    0xb080 : 0xb000));
                return 1;
        }
        return 0;
 }
 
-static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
 {
        static char *texts[] = {
                "Front", "Surround", "CLFE", "Side"
@@ -1903,7 +1966,8 @@ static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        return 0;
 }
 
-static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
@@ -1914,7 +1978,8 @@ static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_el
        return 0;
 }
 
-static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
@@ -2739,7 +2804,8 @@ static int patch_alc880(struct hda_codec *codec)
 
        board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
        if (board_config < 0 || board_config >= ALC880_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
+                      "trying auto-probe from BIOS...\n");
                board_config = ALC880_AUTO;
        }
 
@@ -2750,7 +2816,9 @@ static int patch_alc880(struct hda_codec *codec)
                        alc_free(codec);
                        return err;
                } else if (! err) {
-                       printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS.  Using 3-stack mode...\n");
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using 3-stack mode...\n");
                        board_config = ALC880_3ST;
                }
        }
@@ -3947,7 +4015,8 @@ static int patch_alc260(struct hda_codec *codec)
 
        board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl);
        if (board_config < 0 || board_config >= ALC260_MODEL_LAST) {
-               snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n");
+               snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
+                          "trying auto-probe from BIOS...\n");
                board_config = ALC260_AUTO;
        }
 
@@ -3958,7 +4027,9 @@ static int patch_alc260(struct hda_codec *codec)
                        alc_free(codec);
                        return err;
                } else if (! err) {
-                       printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS.  Using base mode...\n");
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
                        board_config = ALC260_BASIC;
                }
        }
@@ -4320,9 +4391,12 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = {
 static struct hda_board_config alc882_cfg_tbl[] = {
        { .modelname = "3stack-dig", .config = ALC882_3ST_DIG },
        { .modelname = "6stack-dig", .config = ALC882_6ST_DIG },
-       { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* MSI  */
-       { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* Foxconn */
-       { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* ECS */
+       { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
+         .config = ALC882_6ST_DIG }, /* MSI  */
+       { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
+         .config = ALC882_6ST_DIG }, /* Foxconn */
+       { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
+         .config = ALC882_6ST_DIG }, /* ECS to Intel*/
        { .modelname = "auto", .config = ALC882_AUTO },
        {}
 };
@@ -4439,10 +4513,6 @@ static void alc882_auto_init(struct hda_codec *codec)
        alc882_auto_init_analog_input(codec);
 }
 
-/*
- *  ALC882 Headphone poll in 3.5.1a or 3.5.2
- */
-
 static int patch_alc882(struct hda_codec *codec)
 {
        struct alc_spec *spec;
@@ -4457,7 +4527,8 @@ static int patch_alc882(struct hda_codec *codec)
        board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl);
 
        if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC882, trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
+                      "trying auto-probe from BIOS...\n");
                board_config = ALC882_AUTO;
        }
 
@@ -4468,7 +4539,9 @@ static int patch_alc882(struct hda_codec *codec)
                        alc_free(codec);
                        return err;
                } else if (! err) {
-                       printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS.  Using base mode...\n");
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
                        board_config = ALC882_3ST_DIG;
                }
        }
@@ -4509,69 +4582,737 @@ static int patch_alc882(struct hda_codec *codec)
 }
 
 /*
- * ALC262 support
+ * ALC883 support
+ *
+ * ALC883 is almost identical with ALC880 but has cleaner and more flexible
+ * configuration.  Each pin widget can choose any input DACs and a mixer.
+ * Each ADC is connected from a mixer of all inputs.  This makes possible
+ * 6-channel independent captures.
+ *
+ * In addition, an independent DAC for the multi-playback (not used in this
+ * driver yet).
  */
+#define ALC883_DIGOUT_NID      0x06
+#define ALC883_DIGIN_NID       0x0a
 
-#define ALC262_DIGOUT_NID      ALC880_DIGOUT_NID
-#define ALC262_DIGIN_NID       ALC880_DIGIN_NID
+static hda_nid_t alc883_dac_nids[4] = {
+       /* front, rear, clfe, rear_surr */
+       0x02, 0x04, 0x03, 0x05
+};
 
-#define alc262_dac_nids                alc260_dac_nids
-#define alc262_adc_nids                alc882_adc_nids
-#define alc262_adc_nids_alt    alc882_adc_nids_alt
+static hda_nid_t alc883_adc_nids[2] = {
+       /* ADC1-2 */
+       0x08, 0x09,
+};
+/* input MUX */
+/* FIXME: should be a matrix-type input source selection */
 
-#define alc262_modes           alc260_modes
-#define alc262_capture_source  alc882_capture_source
+static struct hda_input_mux alc883_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+#define alc883_mux_enum_info alc_mux_enum_info
+#define alc883_mux_enum_get alc_mux_enum_get
 
-static struct snd_kcontrol_new alc262_base_mixer[] = {
+static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       const struct hda_input_mux *imux = spec->input_mux;
+       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
+       hda_nid_t nid = capture_mixers[adc_idx];
+       unsigned int *cur_val = &spec->cur_mux[adc_idx];
+       unsigned int i, idx;
+
+       idx = ucontrol->value.enumerated.item[0];
+       if (idx >= imux->num_items)
+               idx = imux->num_items - 1;
+       if (*cur_val == idx && ! codec->in_resume)
+               return 0;
+       for (i = 0; i < imux->num_items; i++) {
+               unsigned int v = (i == idx) ? 0x7000 : 0x7080;
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   v | (imux->items[i].index << 8));
+       }
+       *cur_val = idx;
+       return 1;
+}
+/*
+ * 2ch mode
+ */
+static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
+       { 2, NULL }
+};
+
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc883_3ST_ch2_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc883_3ST_ch6_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static struct hda_channel_mode alc883_3ST_6ch_modes[2] = {
+       { 2, alc883_3ST_ch2_init },
+       { 6, alc883_3ST_ch6_init },
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc883_sixstack_ch6_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc883_sixstack_ch8_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { } /* end */
+};
+
+static struct hda_channel_mode alc883_sixstack_modes[2] = {
+       { 6, alc883_sixstack_ch6_init },
+       { 8, alc883_sixstack_ch8_init },
+};
+
+/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+ *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+ */
+
+static struct snd_kcontrol_new alc883_base_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-          HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc883_mux_enum_info,
+               .get = alc883_mux_enum_get,
+               .put = alc883_mux_enum_put,
+       },
        { } /* end */
 };
 
-#define alc262_capture_mixer           alc882_capture_mixer
-#define alc262_capture_alt_mixer       alc882_capture_alt_mixer
+static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc883_mux_enum_info,
+               .get = alc883_mux_enum_get,
+               .put = alc883_mux_enum_put,
+       },
+       { } /* end */
+};
 
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static struct hda_verb alc262_init_verbs[] = {
-       /*
-        * Unmute ADC0-2 and set the default input to mic-in
-        */
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc883_mux_enum_info,
+               .get = alc883_mux_enum_get,
+               .put = alc883_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc883_chmode_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
+       { } /* end */
+};
+
+static struct hda_verb alc883_init_verbs[] = {
+       /* ADC1: mute amp left and right */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* ADC2: mute amp left and right */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* Front mixer: unmute input/output amp left and right (volume = 0) */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Rear mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* CLFE mixer */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Side mixer */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 
-       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-        * mixer widget
-        * Note: PASD motherboards uses the Line In 2 as the input for front panel
-        * mic (mic 2)
-        */
-       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
 
-       /*
+       /* Front Pin: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Rear Pin: output 1 (0x0d) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       /* CLFE Pin: output 2 (0x0e) */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* Side Pin: output 3 (0x0f) */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+       /* Mic (rear) pin: input vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin: input */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line-2 In: Headphone output (output 0 - 0x0c) */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* CD pin widget for input */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+       { }
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc883_auto_init_verbs[] = {
+       /*
+        * Unmute ADC0-2 and set the default input to mic-in
+        */
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        * Note: PASD motherboards uses the Line In 2 as the input for front panel
+        * mic (mic 2)
+        */
+       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+       /*
+        * Set up output mixers (0x0c - 0x0f)
+        */
+       /* set vol=0 to output mixers */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+       /* Input mixer1 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       //{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+       /* Input mixer2 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       //{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+       { }
+};
+
+/* capture mixer elements */
+static struct snd_kcontrol_new alc883_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc882_mux_enum_info,
+               .get = alc882_mux_enum_get,
+               .put = alc882_mux_enum_put,
+       },
+       { } /* end */
+};
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc883_pcm_analog_playback     alc880_pcm_analog_playback
+#define alc883_pcm_analog_capture      alc880_pcm_analog_capture
+#define alc883_pcm_digital_playback    alc880_pcm_digital_playback
+#define alc883_pcm_digital_capture     alc880_pcm_digital_capture
+
+/*
+ * configuration and preset
+ */
+static struct hda_board_config alc883_cfg_tbl[] = {
+       { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG },
+       { .modelname = "6stack-dig", .config = ALC883_6ST_DIG },
+       { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD },
+       { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
+         .config = ALC883_6ST_DIG }, /* MSI  */
+       { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
+         .config = ALC883_6ST_DIG }, /* Foxconn */
+       { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
+         .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/
+       { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d,
+         .config = ALC883_3ST_6ch },
+       { .modelname = "auto", .config = ALC883_AUTO },
+       {}
+};
+
+static struct alc_config_preset alc883_presets[] = {
+       [ALC883_3ST_2ch_DIG] = {
+               .mixers = { alc883_3ST_2ch_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC883_3ST_6ch_DIG] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .input_mux = &alc883_capture_source,
+       },      
+       [ALC883_3ST_6ch] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .input_mux = &alc883_capture_source,
+       },      
+       [ALC883_6ST_DIG] = {
+               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC888_DEMO_BOARD] = {
+               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .input_mux = &alc883_capture_source,
+       },
+};
+
+
+/*
+ * BIOS auto configuration
+ */
+static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
+                                             hda_nid_t nid, int pin_type,
+                                             int dac_idx)
+{
+       /* set as output */
+       struct alc_spec *spec = codec->spec;
+       int idx; 
+       
+       if (spec->multiout.dac_nids[dac_idx] == 0x25)
+               idx = 4;
+       else
+               idx = spec->multiout.dac_nids[dac_idx] - 2;
+
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           pin_type);
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           AMP_OUT_UNMUTE);
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
+
+}
+
+static void alc883_auto_init_multi_out(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i <= HDA_SIDE; i++) {
+               hda_nid_t nid = spec->autocfg.line_out_pins[i]; 
+               if (nid)
+                       alc883_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
+       }
+}
+
+static void alc883_auto_init_hp_out(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t pin;
+
+       pin = spec->autocfg.hp_pin;
+       if (pin) /* connect to front */
+               /* use dac 0 */
+               alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+}
+
+#define alc883_is_input_pin(nid)       alc880_is_input_pin(nid)
+#define ALC883_PIN_CD_NID              ALC880_PIN_CD_NID
+
+static void alc883_auto_init_analog_input(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               hda_nid_t nid = spec->autocfg.input_pins[i];
+               if (alc883_is_input_pin(nid)) {
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                           (i <= AUTO_PIN_FRONT_MIC ?
+                                            PIN_VREF80 : PIN_IN));
+                       if (nid != ALC883_PIN_CD_NID)
+                               snd_hda_codec_write(codec, nid, 0,
+                                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                                   AMP_OUT_MUTE);
+               }
+       }
+}
+
+/* almost identical with ALC880 parser... */
+static int alc883_parse_auto_config(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int err = alc880_parse_auto_config(codec);
+
+       if (err < 0)
+               return err;
+       else if (err > 0)
+               /* hack - override the init verbs */
+               spec->init_verbs[0] = alc883_auto_init_verbs;
+                spec->mixers[spec->num_mixers] = alc883_capture_mixer;
+               spec->num_mixers++;
+       return err;
+}
+
+/* additional initialization for auto-configuration model */
+static void alc883_auto_init(struct hda_codec *codec)
+{
+       alc883_auto_init_multi_out(codec);
+       alc883_auto_init_hp_out(codec);
+       alc883_auto_init_analog_input(codec);
+}
+
+static int patch_alc883(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int err, board_config;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       board_config = snd_hda_check_board_config(codec, alc883_cfg_tbl);
+       if (board_config < 0 || board_config >= ALC883_MODEL_LAST) {
+               printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
+                      "trying auto-probe from BIOS...\n");
+               board_config = ALC883_AUTO;
+       }
+
+       if (board_config == ALC883_AUTO) {
+               /* automatic parse from the BIOS config */
+               err = alc883_parse_auto_config(codec);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               } else if (! err) {
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
+                       board_config = ALC883_3ST_2ch_DIG;
+               }
+       }
+
+       if (board_config != ALC883_AUTO)
+               setup_preset(spec, &alc883_presets[board_config]);
+
+       spec->stream_name_analog = "ALC883 Analog";
+       spec->stream_analog_playback = &alc883_pcm_analog_playback;
+       spec->stream_analog_capture = &alc883_pcm_analog_capture;
+
+       spec->stream_name_digital = "ALC883 Digital";
+       spec->stream_digital_playback = &alc883_pcm_digital_playback;
+       spec->stream_digital_capture = &alc883_pcm_digital_capture;
+
+       spec->adc_nids = alc883_adc_nids;
+       spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+
+       codec->patch_ops = alc_patch_ops;
+       if (board_config == ALC883_AUTO)
+               spec->init_hook = alc883_auto_init;
+
+       return 0;
+}
+
+/*
+ * ALC262 support
+ */
+
+#define ALC262_DIGOUT_NID      ALC880_DIGOUT_NID
+#define ALC262_DIGIN_NID       ALC880_DIGIN_NID
+
+#define alc262_dac_nids                alc260_dac_nids
+#define alc262_adc_nids                alc882_adc_nids
+#define alc262_adc_nids_alt    alc882_adc_nids_alt
+
+#define alc262_modes           alc260_modes
+#define alc262_capture_source  alc882_capture_source
+
+static struct snd_kcontrol_new alc262_base_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
+          HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
+       { } /* end */
+};
+
+#define alc262_capture_mixer           alc882_capture_mixer
+#define alc262_capture_alt_mixer       alc882_capture_alt_mixer
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc262_init_verbs[] = {
+       /*
+        * Unmute ADC0-2 and set the default input to mic-in
+        */
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        * Note: PASD motherboards uses the Line In 2 as the input for front panel
+        * mic (mic 2)
+        */
+       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+       /*
         * Set up output mixers (0x0c - 0x0e)
         */
        /* set vol=0 to output mixers */
@@ -4645,6 +5386,17 @@ static struct hda_input_mux alc262_fujitsu_capture_source = {
        },
 };
 
+static struct hda_input_mux alc262_HP_capture_source = {
+       .num_items = 5,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x3 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+               { "AUX IN", 0x6 },
+       },
+};
+
 /* mute/unmute internal speaker according to the hp jack and mute state */
 static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
 {
@@ -4868,6 +5620,93 @@ static struct hda_verb alc262_volume_init_verbs[] = {
        { }
 };
 
+static struct hda_verb alc262_HP_BPC_init_verbs[] = {
+       /*
+        * Unmute ADC0-2 and set the default input to mic-in
+        */
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        * Note: PASD motherboards uses the Line In 2 as the input for front panel
+        * mic (mic 2)
+        */
+       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
+        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
+       
+       /*
+        * Set up output mixers (0x0c - 0x0e)
+        */
+       /* set vol=0 to output mixers */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+        {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+
+       { }
+};
+
 /* pcm configuration: identiacal with ALC880 */
 #define alc262_pcm_analog_playback     alc880_pcm_analog_playback
 #define alc262_pcm_analog_capture      alc880_pcm_analog_capture
@@ -4928,7 +5767,16 @@ static void alc262_auto_init(struct hda_codec *codec)
 static struct hda_board_config alc262_cfg_tbl[] = {
        { .modelname = "basic", .config = ALC262_BASIC },
        { .modelname = "fujitsu", .config = ALC262_FUJITSU },
-       { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, .config = ALC262_FUJITSU },
+       { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397,
+         .config = ALC262_FUJITSU },
+       { .pci_subvendor = 0x103c, .pci_subdevice = 0x208c,
+         .config = ALC262_HP_BPC }, /* xw4400 */
+       { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014,
+         .config = ALC262_HP_BPC }, /* xw6400 */
+       { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015,
+         .config = ALC262_HP_BPC }, /* xw8400 */
+       { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe,
+         .config = ALC262_HP_BPC }, /* xw9400 */
        { .modelname = "auto", .config = ALC262_AUTO },
        {}
 };
@@ -4956,6 +5804,16 @@ static struct alc_config_preset alc262_presets[] = {
                .input_mux = &alc262_fujitsu_capture_source,
                .unsol_event = alc262_fujitsu_unsol_event,
        },
+       [ALC262_HP_BPC] = {
+               .mixers = { alc262_HP_BPC_mixer },
+               .init_verbs = { alc262_HP_BPC_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_HP_capture_source,
+       },      
 };
 
 static int patch_alc262(struct hda_codec *codec)
@@ -4981,8 +5839,10 @@ static int patch_alc262(struct hda_codec *codec)
 #endif
 
        board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl);
+       
        if (board_config < 0 || board_config >= ALC262_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC262, trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
+                      "trying auto-probe from BIOS...\n");
                board_config = ALC262_AUTO;
        }
 
@@ -4993,7 +5853,9 @@ static int patch_alc262(struct hda_codec *codec)
                        alc_free(codec);
                        return err;
                } else if (! err) {
-                       printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS.  Using base mode...\n");
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
                        board_config = ALC262_BASIC;
                }
        }
@@ -5034,7 +5896,6 @@ static int patch_alc262(struct hda_codec *codec)
        return 0;
 }
 
-
 /*
  *  ALC861 channel source setting (2/6 channel selection for 3-stack)
  */
@@ -5049,9 +5910,11 @@ static struct hda_verb alc861_threestack_ch2_init[] = {
        /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */
        { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
 
-        { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
-        { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, //mic
-        { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, //line in
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
+#if 0
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
+#endif
        { } /* end */
 };
 /*
@@ -5065,11 +5928,13 @@ static struct hda_verb alc861_threestack_ch6_init[] = {
        { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
 
        { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
-        { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
 
-        { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
-        { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, //mic
-        { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, //line in
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+#if 0
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
+#endif
        { } /* end */
 };
 
@@ -5353,6 +6218,11 @@ static hda_nid_t alc861_dac_nids[4] = {
        0x03, 0x06, 0x05, 0x04
 };
 
+static hda_nid_t alc660_dac_nids[3] = {
+       /* front, clfe, surround */
+       0x03, 0x05, 0x06
+};
+
 static hda_nid_t alc861_adc_nids[1] = {
        /* ADC0-2 */
        0x08,
@@ -5605,7 +6475,10 @@ static void alc861_auto_init(struct hda_codec *codec)
  */
 static struct hda_board_config alc861_cfg_tbl[] = {
        { .modelname = "3stack", .config = ALC861_3ST },
-       { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, .config = ALC861_3ST },
+       { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600,
+         .config = ALC861_3ST },
+       { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7,
+         .config = ALC660_3ST },
        { .modelname = "3stack-dig", .config = ALC861_3ST_DIG },
        { .modelname = "6stack-dig", .config = ALC861_6ST_DIG },
        { .modelname = "auto", .config = ALC861_AUTO },
@@ -5648,6 +6521,17 @@ static struct alc_config_preset alc861_presets[] = {
                .adc_nids = alc861_adc_nids,
                .input_mux = &alc861_capture_source,
        },
+       [ALC660_3ST] = {
+               .mixers = { alc861_3ST_mixer },
+               .init_verbs = { alc861_threestack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc660_dac_nids),
+               .dac_nids = alc660_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
+               .channel_mode = alc861_threestack_modes,
+               .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+               .adc_nids = alc861_adc_nids,
+               .input_mux = &alc861_capture_source,
+       },
 };     
 
 
@@ -5664,8 +6548,10 @@ static int patch_alc861(struct hda_codec *codec)
        codec->spec = spec;     
 
         board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl);
+
        if (board_config < 0 || board_config >= ALC861_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC861, trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
+                      "trying auto-probe from BIOS...\n");
                board_config = ALC861_AUTO;
        }
 
@@ -5676,7 +6562,9 @@ static int patch_alc861(struct hda_codec *codec)
                        alc_free(codec);
                        return err;
                } else if (! err) {
-                       printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS.  Using base mode...\n");
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
                   board_config = ALC861_3ST_DIG;
                }
        }
@@ -5707,8 +6595,12 @@ struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
        { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
        { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
-       { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
+       { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
        { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
-       { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
+       { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
+       { .id = 0x10ec0861, .rev = 0x100300, .name = "ALC861",
+         .patch = patch_alc861 },
+        { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
+         .patch = patch_alc861 },
        {} /* terminator */
 };
index 36f199442fdc631307fb99630821f565728ea842..fb4bed0759d182bc78277fb63de4f60b5ee38a18 100644 (file)
@@ -42,6 +42,9 @@
 #define STAC_D945GTP3          1
 #define STAC_D945GTP5          2
 #define STAC_MACMINI           3
+#define STAC_D965_2112         4
+#define STAC_D965_284B         5
+#define STAC_922X_MODELS       6       /* number of 922x models */
 
 struct sigmatel_spec {
        struct snd_kcontrol_new *mixers[4];
@@ -107,10 +110,24 @@ static hda_nid_t stac922x_adc_nids[2] = {
         0x06, 0x07,
 };
 
+static hda_nid_t stac9227_adc_nids[2] = {
+        0x07, 0x08,
+};
+
+#if 0
+static hda_nid_t d965_2112_dac_nids[3] = {
+        0x02, 0x03, 0x05,
+};
+#endif
+
 static hda_nid_t stac922x_mux_nids[2] = {
         0x12, 0x13,
 };
 
+static hda_nid_t stac9227_mux_nids[2] = {
+        0x15, 0x16,
+};
+
 static hda_nid_t stac927x_adc_nids[3] = {
         0x07, 0x08, 0x09
 };
@@ -173,6 +190,24 @@ static struct hda_verb stac922x_core_init[] = {
        {}
 };
 
+static struct hda_verb stac9227_core_init[] = {
+       /* set master volume and direct control */      
+       { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* unmute node 0x1b */
+       { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+       {}
+};
+
+static struct hda_verb d965_2112_core_init[] = {
+       /* set master volume and direct control */      
+       { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* unmute node 0x1b */
+       { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+       /* select node 0x03 as DAC */   
+       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {}
+};
+
 static struct hda_verb stac927x_core_init[] = {
        /* set master volume and direct control */      
        { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -212,6 +247,21 @@ static struct snd_kcontrol_new stac922x_mixer[] = {
        { } /* end */
 };
 
+/* This needs to be generated dynamically based on sequence */
+static struct snd_kcontrol_new stac9227_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Input Source",
+               .count = 1,
+               .info = stac92xx_mux_enum_info,
+               .get = stac92xx_mux_enum_get,
+               .put = stac92xx_mux_enum_put,
+       },
+       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
 static snd_kcontrol_new_t stac927x_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -291,11 +341,17 @@ static unsigned int d945gtp5_pin_configs[10] = {
        0x02a19320, 0x40000100,
 };
 
-static unsigned int *stac922x_brd_tbl[] = {
-       ref922x_pin_configs,
-       d945gtp3_pin_configs,
-       d945gtp5_pin_configs,
-       NULL,           /* STAC_MACMINI */
+static unsigned int d965_2112_pin_configs[10] = {
+       0x0221401f, 0x40000100, 0x40000100, 0x01014011,
+       0x01a19021, 0x01813024, 0x01452130, 0x40000100,
+       0x02a19320, 0x40000100,
+};
+
+static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
+       [STAC_REF] =    ref922x_pin_configs,
+       [STAC_D945GTP3] = d945gtp3_pin_configs,
+       [STAC_D945GTP5] = d945gtp5_pin_configs,
+       [STAC_D965_2112] = d965_2112_pin_configs,
 };
 
 static struct hda_board_config stac922x_cfg_tbl[] = {
@@ -330,6 +386,12 @@ static struct hda_board_config stac922x_cfg_tbl[] = {
        { .pci_subvendor = 0x8384,
          .pci_subdevice = 0x7680,
          .config = STAC_MACMINI },     /* Apple Mac Mini (early 2006) */
+       { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x2112,
+         .config = STAC_D965_2112 },
+       { .pci_subvendor = PCI_VENDOR_ID_INTEL,
+         .pci_subdevice = 0x284b,
+         .config = STAC_D965_284B },
        {} /* terminator */
 };
 
@@ -713,7 +775,8 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf
  * A and B is not supported.
  */
 /* fill in the dac_nids table from the parsed pin configuration */
-static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
+static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
+                                      const struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
        hda_nid_t nid;
@@ -732,10 +795,13 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct aut
 }
 
 /* add playback controls from the parsed DAC table */
-static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, const struct auto_pin_cfg *cfg)
+static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec,
+                                              const struct auto_pin_cfg *cfg)
 {
        char name[32];
-       static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
+       static const char *chname[4] = {
+               "Front", "Surround", NULL /*CLFE*/, "Side"
+       };
        hda_nid_t nid;
        int i, err;
 
@@ -893,10 +959,12 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                return err;
        if (! spec->autocfg.line_outs)
                return 0; /* can't find valid pin config */
+
        if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
                return err;
-       if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
-               return err;
+       if (spec->multiout.num_dacs == 0)
+               if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
+                       return err;
 
        if ((err = stac92xx_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
            (err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg)) < 0 ||
@@ -1194,7 +1262,8 @@ static int patch_stac922x(struct hda_codec *codec)
        codec->spec = spec;
        spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl);
        if (spec->board_config < 0)
-                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, using BIOS defaults\n");
+                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
+                           "using BIOS defaults\n");
        else if (stac922x_brd_tbl[spec->board_config] != NULL) {
                spec->num_pins = 10;
                spec->pin_nids = stac922x_pin_nids;
@@ -1210,6 +1279,25 @@ static int patch_stac922x(struct hda_codec *codec)
        spec->mixer = stac922x_mixer;
 
        spec->multiout.dac_nids = spec->dac_nids;
+       
+       switch (spec->board_config) {
+       case STAC_D965_2112:
+               spec->adc_nids = stac9227_adc_nids;
+               spec->mux_nids = stac9227_mux_nids;
+#if 0
+               spec->multiout.dac_nids = d965_2112_dac_nids;
+               spec->multiout.num_dacs = ARRAY_SIZE(d965_2112_dac_nids);
+#endif
+               spec->init = d965_2112_core_init;
+               spec->mixer = stac9227_mixer;
+               break;
+       case STAC_D965_284B:
+               spec->adc_nids = stac9227_adc_nids;
+               spec->mux_nids = stac9227_mux_nids;
+               spec->init = stac9227_core_init;
+               spec->mixer = stac9227_mixer;
+               break;
+       }
 
        err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
        if (err < 0) {
index b5754b32b802cffa499226bfd85a5b6798f3e280..fec9440cb310485e8c6cb55c275172e60220ba82 100644 (file)
@@ -87,12 +87,25 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
  * initialize the chips on M-Audio Revolution cards
  */
 
+static unsigned int revo71_num_stereo_front[] = {2};
+static char *revo71_channel_names_front[] = {"PCM Playback Volume"};
+
+static unsigned int revo71_num_stereo_surround[] = {1, 1, 2, 2};
+static char *revo71_channel_names_surround[] = {"PCM Center Playback Volume", "PCM LFE Playback Volume",
+                                               "PCM Side Playback Volume", "PCM Rear Playback Volume"};
+
+static unsigned int revo51_num_stereo[] = {2, 1, 1, 2};
+static char *revo51_channel_names[] = {"PCM Playback Volume", "PCM Center Playback Volume",
+                                       "PCM LFE Playback Volume", "PCM Rear Playback Volume"};
+
 static struct snd_akm4xxx akm_revo_front __devinitdata = {
        .type = SND_AK4381,
        .num_dacs = 2,
        .ops = {
                .set_rate_val = revo_set_rate_val
-       }
+       },
+       .num_stereo = revo71_num_stereo_front,
+       .channel_names = revo71_channel_names_front
 };
 
 static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
@@ -113,7 +126,9 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = {
        .num_dacs = 6,
        .ops = {
                .set_rate_val = revo_set_rate_val
-       }
+       },
+       .num_stereo = revo71_num_stereo_surround,
+       .channel_names = revo71_channel_names_surround
 };
 
 static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
@@ -133,7 +148,9 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = {
        .num_dacs = 6,
        .ops = {
                .set_rate_val = revo_set_rate_val
-       }
+       },
+       .num_stereo = revo51_num_stereo,
+       .channel_names = revo51_channel_names
 };
 
 static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
index dcf4029483474bd3790b6ef45e7e71d434491d8b..e5511606af04e9e58ff4b91f26a05aba41d20fba 100644 (file)
@@ -1441,10 +1441,10 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci,
 
        strcpy(card->driver, "SonicVibes");
        strcpy(card->shortname, "S3 SonicVibes");
-       sprintf(card->longname, "%s rev %i at 0x%lx, irq %i",
+       sprintf(card->longname, "%s rev %i at 0x%llx, irq %i",
                card->shortname,
                sonic->revision,
-               pci_resource_start(pci, 1),
+               (unsigned long long)pci_resource_start(pci, 1),
                sonic->irq);
 
        if ((err = snd_sonicvibes_pcm(sonic, 0, NULL)) < 0) {
index b678814975c9e1dd93297033966a527172ec8b28..be98f63773392af7e9afa04c748acffc5d5c8b94 100644 (file)
@@ -1170,9 +1170,10 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
                                               chip->rsrc[i].start + 1,
                                               rnames[i]) == NULL) {
                                printk(KERN_ERR "snd: can't request rsrc "
-                                      " %d (%s: 0x%08lx:%08lx)\n",
-                                      i, rnames[i], chip->rsrc[i].start,
-                                      chip->rsrc[i].end);
+                                      " %d (%s: 0x%016lx:%016lx)\n",
+                                      i, rnames[i],
+                                      (unsigned long long)chip->rsrc[i].start,
+                                      (unsigned long long)chip->rsrc[i].end);
                                err = -ENODEV;
                                goto __error;
                        }
@@ -1201,9 +1202,10 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
                                               chip->rsrc[i].start + 1,
                                               rnames[i]) == NULL) {
                                printk(KERN_ERR "snd: can't request rsrc "
-                                      " %d (%s: 0x%08lx:%08lx)\n",
-                                      i, rnames[i], chip->rsrc[i].start,
-                                      chip->rsrc[i].end);
+                                      " %d (%s: 0x%016llx:%016llx)\n",
+                                      i, rnames[i],
+                                      (unsigned long long)chip->rsrc[i].start,
+                                      (unsigned long long)chip->rsrc[i].end);
                                err = -ENODEV;
                                goto __error;
                        }
diff --git a/sound/ppc/toonie.c b/sound/ppc/toonie.c
deleted file mode 100644 (file)
index e69de29..0000000
index 6f849720aef35fa08552dc1bc8e16fc84383e0aa..7535ec821dcf8dfb53a55046853ad86b0cbff54d 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/sound.h>
 #include <linux/major.h>
 #include <linux/kmod.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/device.h>
 
 #define SOUND_STEP 16
@@ -172,8 +171,6 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati
        else
                sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
 
-       devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor),
-                       S_IFCHR | mode, s->name);
        class_device_create(sound_class, NULL, MKDEV(SOUND_MAJOR, s->unit_minor),
                            dev, s->name+6);
        return r;
@@ -197,7 +194,6 @@ static void sound_remove_unit(struct sound_unit **list, int unit)
        p = __sound_remove_unit(list, unit);
        spin_unlock(&sound_loader_lock);
        if (p) {
-               devfs_remove(p->name);
                class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
                kfree(p);
        }
@@ -570,7 +566,6 @@ static void __exit cleanup_soundcore(void)
        /* We have nothing to really do here - we know the lists must be
           empty */
        unregister_chrdev(SOUND_MAJOR, "sound");
-       devfs_remove("sound");
        class_destroy(sound_class);
 }
 
@@ -580,7 +575,6 @@ static int __init init_soundcore(void)
                printk(KERN_ERR "soundcore: sound device already in use.\n");
                return -EBUSY;
        }
-       devfs_mk_dir ("sound");
        sound_class = class_create(THIS_MODULE, "sound");
        if (IS_ERR(sound_class))
                return PTR_ERR(sound_class);
index da54d04a3e3a4a9af73dd32d9689c808d77edba3..d9d14c2707dbf922a622b5889b9c2b78af74068b 100644 (file)
@@ -2037,10 +2037,10 @@ static int __init cs4231_sbus_attach(struct sbus_dev *sdev)
        if (err)
                return err;
 
-       sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d",
+       sprintf(card->longname, "%s at 0x%02lx:0x%016lx, irq %d",
                card->shortname,
                rp->flags & 0xffL,
-               rp->start,
+               (unsigned long long)rp->start,
                sdev->irqs[0]);
 
        if ((err = snd_cs4231_sbus_create(card, sdev, dev, &cp)) < 0) {
index 5eecdd09a79ddd91a3345eb92f7a82303d474a3e..a7489a3dd75ac4f68fc328f128332e760a77a28f 100644 (file)
@@ -2645,9 +2645,9 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev)
        strcpy(card->driver, "DBRI");
        strcpy(card->shortname, "Sun DBRI");
        rp = &sdev->resource[0];
-       sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d",
+       sprintf(card->longname, "%s at 0x%02lx:0x%016lx, irq %d",
                card->shortname,
-               rp->flags & 0xffL, rp->start, irq.pri);
+               rp->flags & 0xffL, (unsigned long long)rp->start, irq.pri);
 
        if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) {
                snd_card_free(card);
index 627de9525a32594b2ce2fcb84325b43189cbc0a6..d32d83d970cc9807f0fc19d31f35f5cb8d49104e 100644 (file)
@@ -3095,6 +3095,32 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
        return 0;
 }
 
+/*
+ * C-Media CM106/CM106+ have four 16-bit internal registers that are nicely
+ * documented in the device's data sheet.
+ */
+static int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 value)
+{
+       u8 buf[4];
+       buf[0] = 0x20;
+       buf[1] = value & 0xff;
+       buf[2] = (value >> 8) & 0xff;
+       buf[3] = reg;
+       return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION,
+                              USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
+                              0, 0, &buf, 4, 1000);
+}
+
+static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
+{
+       /*
+        * Enable line-out driver mode, set headphone source to front
+        * channels, enable stereo mic.
+        */
+       return snd_usb_cm106_write_int_reg(dev, 2, 0x8004);
+}
+
+
 /*
  * Setup quirks
  */
@@ -3365,6 +3391,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                        goto __err_val;
        }
 
+       /* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
+       if (id == USB_ID(0x10f5, 0x0200)) {
+               if (snd_usb_cm106_boot_quirk(dev) < 0)
+                       goto __err_val;
+       }
+
        /*
         * found a config.  now register to ALSA
         */